← Commit history

Publish 1.8.3

Kyle Bergstedt ·d8cb7ab404 ·2mo ago ·parent e54a51e
100 files changed +22032 diff truncated
._AdomBasicParts_full.lbr._BRIDGE_VERSION._LICENSE._NEXT-SESSION-bq25792-viewer.md._README.md._SKILL.md._VERBS.md._ad_client.py._adom-bridge-fusion-manifest.json._aps.py._bridge.json._describe.py._eagle_lbr.py._fusion_detect.py._fusion_helper.py._install.sh._install_addin.py._package.json._server.py._start.bat._uninstall.shAdomBasicParts_full.lbr+2768BRIDGE_VERSION+1LICENSE+21NEXT-SESSION-bq25792-viewer.md+76SKILL.md+297VERBS.md+1347ad_client.py+280addin/AdomBridge/._AdomBridge.manifestaddin/AdomBridge/._AdomBridge.pyaddin/AdomBridge/._http_server.pyaddin/AdomBridge/AdomBridge.manifest+12addin/AdomBridge/AdomBridge.py+109addin/AdomBridge/commands/.___init__.pyaddin/AdomBridge/commands/._app_state.pyaddin/AdomBridge/commands/._assembly_bom.pyaddin/AdomBridge/commands/._close_document.pyaddin/AdomBridge/commands/._cloud_documents.pyaddin/AdomBridge/commands/._design_info.pyaddin/AdomBridge/commands/._document_info.pyaddin/AdomBridge/commands/._electron_view.pyaddin/AdomBridge/commands/._electronics.pyaddin/AdomBridge/commands/._export.pyaddin/AdomBridge/commands/._import_file.pyaddin/AdomBridge/commands/._manufacturing.pyaddin/AdomBridge/commands/._modeling.pyaddin/AdomBridge/commands/._open_electronics_file.pyaddin/AdomBridge/commands/._open_lbr.pyaddin/AdomBridge/commands/._parameters.pyaddin/AdomBridge/commands/._physical_properties.pyaddin/AdomBridge/commands/._screenshot.pyaddin/AdomBridge/commands/._silkscreen_capture.pyaddin/AdomBridge/commands/__init__.py+143addin/AdomBridge/commands/app_state.py+127addin/AdomBridge/commands/assembly_bom.py+140addin/AdomBridge/commands/close_document.py+152addin/AdomBridge/commands/cloud_documents.py+1886addin/AdomBridge/commands/design_info.py+98addin/AdomBridge/commands/document_info.py+305addin/AdomBridge/commands/electron_view.py+139addin/AdomBridge/commands/electronics.py+1058addin/AdomBridge/commands/export.py+693addin/AdomBridge/commands/import_file.py+107addin/AdomBridge/commands/manufacturing.py+1185addin/AdomBridge/commands/modeling.py+68addin/AdomBridge/commands/open_electronics_file.py+605addin/AdomBridge/commands/open_lbr.py+186addin/AdomBridge/commands/parameters.py+144addin/AdomBridge/commands/physical_properties.py+64addin/AdomBridge/commands/screenshot.py+136addin/AdomBridge/commands/silkscreen_capture.py+308addin/AdomBridge/http_server.py+479addin/AdomBridge/resources/cam/._jlcpcb-2layers.camaddin/AdomBridge/resources/cam/._jlcpcb-4layers.camaddin/AdomBridge/resources/cam/jlcpcb-2layers.cam+245addin/AdomBridge/resources/cam/jlcpcb-4layers.cam+262addin/AdomBridge/resources/dru/._Adom-InstaPCB-2-Layer.edruaddin/AdomBridge/resources/dru/._Adom-InstaPCB-4-Layer.edruaddin/AdomBridge/resources/dru/._AdomDefaults-jlcpcb-2layers-accurate.edruaddin/AdomBridge/resources/dru/._AdomDefaults-jlcpcb-4layers-accurate.edruaddin/AdomBridge/resources/dru/Adom-InstaPCB-2-Layer.edru+165addin/AdomBridge/resources/dru/Adom-InstaPCB-4-Layer.edru+183addin/AdomBridge/resources/dru/AdomDefaults-jlcpcb-2layers-accurate.edru+165addin/AdomBridge/resources/dru/AdomDefaults-jlcpcb-4layers-accurate.edru+183addin/AdomBridge/resources/ulp/._detect_layers.ulpaddin/AdomBridge/resources/ulp/detect_layers.ulp+81adom-bridge-fusion-manifest.json+13aps.py+1416bridge.json+190describe.py+252eagle_lbr.py+270examples/._ADS8588SIPM.fusion.lbrexamples/._ADS8588SIPM.stepexamples/._jst_connector_generator.pyexamples/._jst_ph_connector.pyexamples/ADS8588SIPM.fusion.lbr+294examples/ADS8588SIPM.step+4880examples/jst_connector_generator.py+130examples/jst_ph_connector.py+115fusion_detect.py+254
._AdomBasicParts_full.lbradded
⋯ 1 unchanged line ⋯
._BRIDGE_VERSIONadded
⋯ 1 unchanged line ⋯
._LICENSEadded
⋯ 1 unchanged line ⋯
._NEXT-SESSION-bq25792-viewer.mdadded
⋯ 1 unchanged line ⋯
._README.mdadded
⋯ 1 unchanged line ⋯
._SKILL.mdadded
⋯ 1 unchanged line ⋯
._VERBS.mdadded
⋯ 1 unchanged line ⋯
._ad_client.pyadded
⋯ 1 unchanged line ⋯
._adom-bridge-fusion-manifest.jsonadded
⋯ 1 unchanged line ⋯
._aps.pyadded
⋯ 1 unchanged line ⋯
._bridge.jsonadded
⋯ 1 unchanged line ⋯
._describe.pyadded
⋯ 1 unchanged line ⋯
._eagle_lbr.pyadded
⋯ 1 unchanged line ⋯
._fusion_detect.pyadded
⋯ 1 unchanged line ⋯
._fusion_helper.pyadded
⋯ 1 unchanged line ⋯
._install.shadded
⋯ 1 unchanged line ⋯
._install_addin.pyadded
⋯ 1 unchanged line ⋯
._package.jsonadded
⋯ 1 unchanged line ⋯
._server.pyadded
⋯ 1 unchanged line ⋯
._start.batadded
⋯ 1 unchanged line ⋯
._uninstall.shadded
⋯ 1 unchanged line ⋯
AdomBasicParts_full.lbradded+2768
@@ -0,0 +1,2768 @@+<?xml version="1.0" encoding="utf-8"?>+<!DOCTYPE eagle SYSTEM "eagle.dtd">+<eagle version="9.6.2">+<drawing>+<settings><setting alwaysvectorfont="no"/></settings>+<grid distance="0.1" unitdist="inch" unit="inch" style="lines" multiple="1" display="no" altdistance="0.01" altunitdist="inch" altunit="inch"/>+<layers>+<layer number="1" name="Top" color="4" fill="1" visible="yes" active="yes"/>+<layer number="16" name="Bottom" color="1" fill="1" visible="yes" active="yes"/>+<layer number="17" name="Pads" color="2" fill="1" visible="yes" active="yes"/>+<layer number="18" name="Vias" color="2" fill="1" visible="yes" active="yes"/>+<layer number="19" name="Unrouted" color="6" fill="1" visible="yes" active="yes"/>+<layer number="20" name="Dimension" color="15" fill="1" visible="yes" active="yes"/>+<layer number="21" name="tPlace" color="7" fill="1" visible="yes" active="yes"/>+<layer number="22" name="bPlace" color="7" fill="1" visible="yes" active="yes"/>+<layer number="23" name="tOrigins" color="15" fill="1" visible="yes" active="yes"/>+<layer number="24" name="bOrigins" color="15" fill="1" visible="yes" active="yes"/>+<layer number="25" name="tNames" color="7" fill="1" visible="yes" active="yes"/>+<layer number="26" name="bNames" color="7" fill="1" visible="yes" active="yes"/>+<layer number="27" name="tValues" color="7" fill="1" visible="yes" active="yes"/>+<layer number="28" name="bValues" color="7" fill="1" visible="yes" active="yes"/>+<layer number="29" name="tStop" color="7" fill="3" visible="no" active="yes"/>+<layer number="30" name="bStop" color="7" fill="6" visible="no" active="yes"/>+<layer number="31" name="tCream" color="7" fill="4" visible="no" active="yes"/>+<layer number="32" name="bCream" color="7" fill="5" visible="no" active="yes"/>+<layer number="33" name="tFinish" color="6" fill="3" visible="no" active="yes"/>+<layer number="34" name="bFinish" color="6" fill="6" visible="no" active="yes"/>+<layer number="35" name="tGlue" color="7" fill="4" visible="no" active="yes"/>+<layer number="36" name="bGlue" color="7" fill="5" visible="no" active="yes"/>+<layer number="37" name="tTest" color="7" fill="1" visible="no" active="yes"/>+<layer number="38" name="bTest" color="7" fill="1" visible="no" active="yes"/>+<layer number="39" name="tKeepout" color="4" fill="11" visible="no" active="yes"/>+<layer number="40" name="bKeepout" color="1" fill="11" visible="no" active="yes"/>+<layer number="41" name="tRestrict" color="4" fill="10" visible="no" active="yes"/>+<layer number="42" name="bRestrict" color="1" fill="10" visible="no" active="yes"/>+<layer number="43" name="vRestrict" color="2" fill="10" visible="no" active="yes"/>+<layer number="44" name="Drills" color="7" fill="1" visible="no" active="yes"/>+<layer number="45" name="Holes" color="7" fill="1" visible="no" active="yes"/>+<layer number="46" name="Milling" color="3" fill="1" visible="no" active="yes"/>+<layer number="47" name="Measures" color="7" fill="1" visible="no" active="yes"/>+<layer number="48" name="Document" color="7" fill="1" visible="yes" active="yes"/>+<layer number="49" name="Reference" color="7" fill="1" visible="yes" active="yes"/>+<layer number="91" name="Nets" color="2" fill="1" visible="yes" active="yes"/>+<layer number="92" name="Busses" color="1" fill="1" visible="yes" active="yes"/>+<layer number="93" name="Pins" color="2" fill="1" visible="no" active="yes"/>+<layer number="94" name="Symbols" color="4" fill="1" visible="yes" active="yes"/>+<layer number="95" name="Names" color="7" fill="1" visible="yes" active="yes"/>+<layer number="96" name="Values" color="7" fill="1" visible="yes" active="yes"/>+<layer number="97" name="Info" color="7" fill="1" visible="yes" active="yes"/>+<layer number="98" name="Guide" color="6" fill="1" visible="yes" active="yes"/>+</layers>+<library>+<description>Resistor</description>+<packages>+<package name="R-0402">+  <description>R-0402</description>+  <smd name="1" x="-0.5000" y="-0.0000" dx="0.6000" dy="0.5000" layer="1"/>+  <smd name="2" x="0.5000" y="-0.0000" dx="0.6000" dy="0.5000" layer="1"/>+  <wire x1="-0.7000" y1="0.5000" x2="-0.2000" y2="0.5000" width="0.127" layer="21"/>+  <wire x1="-0.2000" y1="0.5000" x2="-0.2000" y2="0.5000" width="0.127" layer="21"/>+  <wire x1="-0.2000" y1="0.5000" x2="-0.7000" y2="0.5000" width="0.127" layer="21"/>+  <wire x1="-0.7000" y1="0.5000" x2="-0.7000" y2="0.5000" width="0.127" layer="21"/>+  <text x="0.0000" y="2.8000" size="1.27" layer="25" align="center">&gt;NAME</text>+  <text x="0.0000" y="-2.8000" size="1.27" layer="27" align="center">&gt;VALUE</text>+</package>++<package name="R-0603">+  <description>R-0603</description>+  <smd name="1" x="-0.8000" y="-0.0000" dx="0.9000" dy="1.0000" layer="1"/>+  <smd name="2" x="0.8000" y="-0.0000" dx="0.9000" dy="1.0000" layer="1"/>+  <wire x1="-1.1000" y1="0.7000" x2="-0.5000" y2="0.7000" width="0.127" layer="21"/>+  <wire x1="-0.5000" y1="0.7000" x2="-0.5000" y2="0.7000" width="0.127" layer="21"/>+  <wire x1="-0.5000" y1="0.7000" x2="-1.1000" y2="0.7000" width="0.127" layer="21"/>+  <wire x1="-1.1000" y1="0.7000" x2="-1.1000" y2="0.7000" width="0.127" layer="21"/>+  <text x="0.0000" y="2.8000" size="1.27" layer="25" align="center">&gt;NAME</text>+  <text x="0.0000" y="-2.8000" size="1.27" layer="27" align="center">&gt;VALUE</text>+</package>++<package name="C-0402">+  <description>C-0402</description>+  <smd name="1" x="-0.5000" y="-0.0000" dx="0.6000" dy="0.5000" layer="1"/>+  <smd name="2" x="0.5000" y="-0.0000" dx="0.6000" dy="0.5000" layer="1"/>+  <wire x1="-0.7000" y1="0.5000" x2="-0.2000" y2="0.5000" width="0.127" layer="21"/>+  <wire x1="-0.2000" y1="0.5000" x2="-0.2000" y2="0.5000" width="0.127" layer="21"/>+  <wire x1="-0.2000" y1="0.5000" x2="-0.7000" y2="0.5000" width="0.127" layer="21"/>+  <wire x1="-0.7000" y1="0.5000" x2="-0.7000" y2="0.5000" width="0.127" layer="21"/>+  <text x="0.0000" y="2.8000" size="1.27" layer="25" align="center">&gt;NAME</text>+  <text x="0.0000" y="-2.8000" size="1.27" layer="27" align="center">&gt;VALUE</text>+</package>++<package name="C-0603">+  <description>C-0603</description>+  <smd name="1" x="-0.7750" y="-0.0000" dx="0.9000" dy="0.9500" layer="1"/>+  <smd name="2" x="0.7750" y="-0.0000" dx="0.9000" dy="0.9500" layer="1"/>+  <wire x1="-0.1406" y1="-0.5100" x2="0.1406" y2="-0.5100" width="0.127" layer="21"/>+  <wire x1="0.1406" y1="-0.5100" x2="0.1406" y2="0.5100" width="0.127" layer="21"/>+  <wire x1="0.1406" y1="0.5100" x2="-0.1406" y2="0.5100" width="0.127" layer="21"/>+  <wire x1="-0.1406" y1="0.5100" x2="-0.1406" y2="-0.5100" width="0.127" layer="21"/>+  <text x="0" y="1.1100" size="1.27" layer="25" align="bottom-center">&gt;NAME</text>+  <text x="0" y="-1.1100" size="1.27" layer="27" align="top-center">&gt;VALUE</text>+</package>++<package name="C-0805">+  <description>C-0805</description>+  <smd name="1" x="-0.9125" y="-0.0000" dx="1.0250" dy="1.4000" layer="1"/>+  <smd name="2" x="0.9125" y="-0.0000" dx="1.0250" dy="1.4000" layer="1"/>+  <wire x1="-0.2271" y1="-0.7350" x2="0.2271" y2="-0.7350" width="0.127" layer="21"/>+  <wire x1="0.2271" y1="-0.7350" x2="0.2271" y2="0.7350" width="0.127" layer="21"/>+  <wire x1="0.2271" y1="0.7350" x2="-0.2271" y2="0.7350" width="0.127" layer="21"/>+  <wire x1="-0.2271" y1="0.7350" x2="-0.2271" y2="-0.7350" width="0.127" layer="21"/>+  <text x="0" y="1.3350" size="1.27" layer="25" align="bottom-center">&gt;NAME</text>+  <text x="0" y="-1.3350" size="1.27" layer="27" align="top-center">&gt;VALUE</text>+</package>++<package name="L">+  <description>L</description>+  <smd name="1" x="-0.8000" y="-0.0000" dx="0.9000" dy="1.0000" layer="1"/>+  <smd name="2" x="0.8000" y="-0.0000" dx="0.9000" dy="1.0000" layer="1"/>+  <wire x1="-1.1000" y1="0.7000" x2="-0.5000" y2="0.7000" width="0.127" layer="21"/>+  <wire x1="-0.5000" y1="0.7000" x2="-0.5000" y2="0.7000" width="0.127" layer="21"/>+  <wire x1="-0.5000" y1="0.7000" x2="-1.1000" y2="0.7000" width="0.127" layer="21"/>+  <wire x1="-1.1000" y1="0.7000" x2="-1.1000" y2="0.7000" width="0.127" layer="21"/>+  <text x="0.0000" y="2.8000" size="1.27" layer="25" align="center">&gt;NAME</text>+  <text x="0.0000" y="-2.8000" size="1.27" layer="27" align="center">&gt;VALUE</text>+</package>++<package name="LED-0402">+  <description>LED-0402</description>+  <smd name="1" x="-0.5000" y="-0.0000" dx="0.6000" dy="0.5000" layer="1"/>+  <smd name="2" x="0.5000" y="-0.0000" dx="0.6000" dy="0.5000" layer="1"/>+  <wire x1="-0.7000" y1="0.5000" x2="-0.2000" y2="0.5000" width="0.127" layer="21"/>+  <wire x1="-0.2000" y1="0.5000" x2="-0.2000" y2="0.5000" width="0.127" layer="21"/>+  <wire x1="-0.2000" y1="0.5000" x2="-0.7000" y2="0.5000" width="0.127" layer="21"/>+  <wire x1="-0.7000" y1="0.5000" x2="-0.7000" y2="0.5000" width="0.127" layer="21"/>+  <text x="0.0000" y="2.8000" size="1.27" layer="25" align="center">&gt;NAME</text>+  <text x="0.0000" y="-2.8000" size="1.27" layer="27" align="center">&gt;VALUE</text>+</package>++<package name="LED-0603">+  <description>LED-0603</description>+  <smd name="1" x="-0.8000" y="-0.0000" dx="0.9000" dy="1.0000" layer="1"/>+  <smd name="2" x="0.8000" y="-0.0000" dx="0.9000" dy="1.0000" layer="1"/>+  <wire x1="-1.1000" y1="0.7000" x2="-0.5000" y2="0.7000" width="0.127" layer="21"/>+  <wire x1="-0.5000" y1="0.7000" x2="-0.5000" y2="0.7000" width="0.127" layer="21"/>+  <wire x1="-0.5000" y1="0.7000" x2="-1.1000" y2="0.7000" width="0.127" layer="21"/>+  <wire x1="-1.1000" y1="0.7000" x2="-1.1000" y2="0.7000" width="0.127" layer="21"/>+  <text x="0.0000" y="2.8000" size="1.27" layer="25" align="center">&gt;NAME</text>+  <text x="0.0000" y="-2.8000" size="1.27" layer="27" align="center">&gt;VALUE</text>+</package>++<package name="LED-2020">+  <description>LED-2020</description>+  <smd name="1" x="-0.7500" y="0.4500" dx="0.7000" dy="0.5000" layer="1"/>+  <smd name="2" x="0.7500" y="0.4500" dx="0.7000" dy="0.5000" layer="1"/>+  <smd name="3" x="0.7500" y="-0.4500" dx="0.7000" dy="0.5000" layer="1"/>+  <smd name="4" x="-0.7500" y="-0.4500" dx="0.7000" dy="0.5000" layer="1"/>+  <wire x1="-1.3000" y1="1.1000" x2="-0.5000" y2="1.1000" width="0.127" layer="21"/>+  <wire x1="-0.5000" y1="1.1000" x2="-0.5000" y2="1.1000" width="0.127" layer="21"/>+  <wire x1="-0.5000" y1="1.1000" x2="-1.3000" y2="1.1000" width="0.127" layer="21"/>+  <wire x1="-1.3000" y1="1.1000" x2="-1.3000" y2="1.1000" width="0.127" layer="21"/>+  <text x="0.0000" y="2.8000" size="1.27" layer="25" align="center">&gt;NAME</text>+  <text x="0.0000" y="-2.8000" size="1.27" layer="27" align="center">&gt;VALUE</text>+</package>++<package name="FB-0402">+  <description>FB-0402</description>+  <smd name="1" x="-0.5000" y="-0.0000" dx="0.6000" dy="0.5000" layer="1"/>+  <smd name="2" x="0.5000" y="-0.0000" dx="0.6000" dy="0.5000" layer="1"/>+  <wire x1="-0.7000" y1="0.5000" x2="-0.2000" y2="0.5000" width="0.127" layer="21"/>+  <wire x1="-0.2000" y1="0.5000" x2="-0.2000" y2="0.5000" width="0.127" layer="21"/>+  <wire x1="-0.2000" y1="0.5000" x2="-0.7000" y2="0.5000" width="0.127" layer="21"/>+  <wire x1="-0.7000" y1="0.5000" x2="-0.7000" y2="0.5000" width="0.127" layer="21"/>+  <text x="0.0000" y="2.8000" size="1.27" layer="25" align="center">&gt;NAME</text>+  <text x="0.0000" y="-2.8000" size="1.27" layer="27" align="center">&gt;VALUE</text>+</package>+</packages>+<packages3d>+<package3d name="R-0402" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1" locally_modified="yes" type="model"><description>R-0402</description><packageinstances><packageinstance name="R-0402"/></packageinstances></package3d>+<package3d name="R-0603" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1" locally_modified="yes" type="model"><description>R-0603</description><packageinstances><packageinstance name="R-0603"/></packageinstances></package3d>+<package3d name="C-0402" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1" locally_modified="yes" type="model"><description>C-0402</description><packageinstances><packageinstance name="C-0402"/></packageinstances></package3d>+<package3d name="C-0603" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1" locally_modified="yes" type="model"><description>C-0603</description><packageinstances><packageinstance name="C-0603"/></packageinstances></package3d>+<package3d name="C-0805" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf._exu-nwHSjWYBLSuNRTfWw?version=1" locally_modified="yes" type="model"><description>C-0805</description><packageinstances><packageinstance name="C-0805"/></packageinstances></package3d>+<package3d name="L" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.toRJ3KRhQ3iFxY1AYlZw6g?version=1" locally_modified="yes" type="model"><description>L</description><packageinstances><packageinstance name="L"/></packageinstances></package3d>+<package3d name="LED-0402" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.3un41Jx6QRC1Nmj1n-LAKg?version=1" locally_modified="yes" type="model"><description>LED-0402</description><packageinstances><packageinstance name="LED-0402"/></packageinstances></package3d>+<package3d name="LED-0603" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.gsqgGNviRjuEu9Y0XXoHgA?version=1" locally_modified="yes" type="model"><description>LED-0603</description><packageinstances><packageinstance name="LED-0603"/></packageinstances></package3d>+<package3d name="LED-2020" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.f1DMoARJRDKHbJRzdxrdYA?version=1" locally_modified="yes" type="model"><description>LED-2020</description><packageinstances><packageinstance name="LED-2020"/></packageinstances></package3d>+<package3d name="FB-0402" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.wLUyrxbNTz2S2zho93PcoA?version=1" locally_modified="yes" type="model"><description>FB-0402</description><packageinstances><packageinstance name="FB-0402"/></packageinstances></package3d>+</packages3d>++<symbols>+<symbol name="R-0402">+  <wire x1="-1.016" y1="-2.54" x2="1.016" y2="-2.54" width="0.254" layer="94"/>+  <wire x1="1.016" y1="-2.54" x2="1.016" y2="2.54" width="0.254" layer="94"/>+  <wire x1="1.016" y1="2.54" x2="-1.016" y2="2.54" width="0.254" layer="94"/>+  <wire x1="-1.016" y1="2.54" x2="-1.016" y2="-2.54" width="0.254" layer="94"/>+  <text x="0" y="0" size="1.27" layer="95" align="bottom-center">&gt;NAME</text>+  <text x="0" y="0" size="1.27" layer="96" align="top-center">&gt;VALUE</text>+  <pin name="~" x="0" y="3.81" length="short" direction="pas" rot="R270"/>+  <pin name="~@2" x="0" y="-3.81" length="short" direction="pas" rot="R90"/>+</symbol>++<symbol name="R-0603">+  <wire x1="-1.016" y1="-2.54" x2="1.016" y2="-2.54" width="0.254" layer="94"/>+  <wire x1="1.016" y1="-2.54" x2="1.016" y2="2.54" width="0.254" layer="94"/>+  <wire x1="1.016" y1="2.54" x2="-1.016" y2="2.54" width="0.254" layer="94"/>+  <wire x1="-1.016" y1="2.54" x2="-1.016" y2="-2.54" width="0.254" layer="94"/>+  <text x="0" y="0" size="1.27" layer="95" align="bottom-center">&gt;NAME</text>+  <text x="0" y="0" size="1.27" layer="96" align="top-center">&gt;VALUE</text>+  <pin name="~" x="0" y="3.81" length="short" direction="pas" rot="R270"/>+  <pin name="~@2" x="0" y="-3.81" length="short" direction="pas" rot="R90"/>+</symbol>++<symbol name="C-0402">+  <text x="0" y="10" size="1.27" layer="95" align="bottom-center">&gt;NAME</text>+  <text x="0" y="-10" size="1.27" layer="96" align="top-center">&gt;VALUE</text>+  <pin name="~" x="0" y="3.81" length="middle" direction="pas" rot="R270"/>+  <pin name="~@2" x="0" y="-3.81" length="middle" direction="pas" rot="R90"/>+</symbol>++<symbol name="C-0603">+  <text x="0" y="10" size="1.27" layer="95" align="bottom-center">&gt;NAME</text>+  <text x="0" y="-10" size="1.27" layer="96" align="top-center">&gt;VALUE</text>+  <pin name="~" x="0" y="3.81" length="middle" direction="pas" rot="R270"/>+  <pin name="~@2" x="0" y="-3.81" length="middle" direction="pas" rot="R90"/>+</symbol>++<symbol name="C-0805">+  <text x="0" y="10" size="1.27" layer="95" align="bottom-center">&gt;NAME</text>+  <text x="0" y="-10" size="1.27" layer="96" align="top-center">&gt;VALUE</text>+  <pin name="~" x="0" y="3.81" length="middle" direction="pas" rot="R270"/>+  <pin name="~@2" x="0" y="-3.81" length="middle" direction="pas" rot="R90"/>+</symbol>++<symbol name="L">+  <text x="0" y="10" size="1.27" layer="95" align="bottom-center">&gt;NAME</text>+  <text x="0" y="-10" size="1.27" layer="96" align="top-center">&gt;VALUE</text>+  <pin name="1" x="0" y="3.81" length="short" direction="pas" rot="R270"/>+  <pin name="2" x="0" y="-3.81" length="short" direction="pas" rot="R90"/>+</symbol>++<symbol name="LED-0402">+  <text x="0" y="10" size="1.27" layer="95" align="bottom-center">&gt;NAME</text>+  <text x="0" y="-10" size="1.27" layer="96" align="top-center">&gt;VALUE</text>+  <pin name="K" x="-3.81" y="0" length="short" direction="pas"/>+  <pin name="A" x="3.81" y="0" length="short" direction="pas" rot="R180"/>+</symbol>++<symbol name="LED-0603">+  <text x="0" y="10" size="1.27" layer="95" align="bottom-center">&gt;NAME</text>+  <text x="0" y="-10" size="1.27" layer="96" align="top-center">&gt;VALUE</text>+  <pin name="K" x="-3.81" y="0" length="short" direction="pas"/>+  <pin name="A" x="3.81" y="0" length="short" direction="pas" rot="R180"/>+</symbol>++<symbol name="LED-2020">+  <wire x1="-10.16" y1="2.54" x2="10.16" y2="2.54" width="0.254" layer="94"/>+  <wire x1="10.16" y1="2.54" x2="10.16" y2="-15.43" width="0.254" layer="94"/>+  <wire x1="10.16" y1="-15.43" x2="-10.16" y2="-15.43" width="0.254" layer="94"/>+  <wire x1="-10.16" y1="-15.43" x2="-10.16" y2="2.54" width="0.254" layer="94"/>+  <text x="0" y="5.08" size="1.27" layer="95" align="bottom-center">&gt;NAME</text>+  <text x="0" y="-17.97" size="1.27" layer="96" align="top-center">&gt;VALUE</text>+  <pin name="DOUT" x="-12.7" y="-2" length="short" direction="out"/>+  <pin name="DIN" x="-12.7" y="-4.54" length="short" direction="in"/>+  <pin name="VSS" x="-12.7" y="-12.89" length="short" direction="pwr"/>+  <pin name="VDD" x="12.7" y="-2" length="short" direction="pwr" rot="R180"/>+  <text x="-9.16" y="0" size="0.762" layer="94" font="vector" ratio="15">DATA</text>+  <text x="-9.16" y="-10.89" size="0.762" layer="94" font="vector" ratio="15">GROUND</text>+  <text x="9.16" y="0" size="0.762" layer="94" font="vector" ratio="15" align="right">POWER</text>+</symbol>++<symbol name="FB-0402">+  <text x="0" y="10" size="1.27" layer="95" align="bottom-center">&gt;NAME</text>+  <text x="0" y="-10" size="1.27" layer="96" align="top-center">&gt;VALUE</text>+  <pin name="1" x="0" y="3.81" length="short" direction="pas" rot="R270"/>+  <pin name="2" x="0" y="-3.81" length="short" direction="pas" rot="R90"/>+</symbol>+</symbols>+<devicesets>+<deviceset name="R-0402-0R" prefix="R">+  <description>Resistor 0Ω 0402 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="0Ω" constant="no"/><attribute name="MPN" value="CQ02WGF0000TCE" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ02WGF0000TCE" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-1R" prefix="R">+  <description>Resistor 1Ω 0402 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1Ω" constant="no"/><attribute name="MPN" value="CQ02WGF100KTCE" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ02WGF100KTCE" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-1R5" prefix="R">+  <description>Resistor 1.5Ω 0402 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1.5Ω" constant="no"/><attribute name="MPN" value="CQ02WGF150KTCE" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ02WGF150KTCE" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-2R2" prefix="R">+  <description>Resistor 2.2Ω 0402 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="2.2Ω" constant="no"/><attribute name="MPN" value="CQ02WGF220KTCE" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ02WGF220KTCE" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-3R3" prefix="R">+  <description>Resistor 3.3Ω 0402 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="3.3Ω" constant="no"/><attribute name="MPN" value="CQ02WGF330KTCE" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ02WGF330KTCE" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-4R7" prefix="R">+  <description>Resistor 4.7Ω 0402 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="4.7Ω" constant="no"/><attribute name="MPN" value="CQ02WGF470KTCE" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ02WGF470KTCE" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-6R8" prefix="R">+  <description>Resistor 6.8Ω 0402 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="6.8Ω" constant="no"/><attribute name="MPN" value="CQ02WGF680KTCE" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ02WGF680KTCE" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-10R" prefix="R">+  <description>Resistor 10Ω 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="10Ω" constant="no"/><attribute name="MPN" value="CR0402-FX-10R0GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-10R0GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-15R" prefix="R">+  <description>Resistor 15Ω 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="15Ω" constant="no"/><attribute name="MPN" value="CR0402-FX-15R0GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-15R0GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-22R" prefix="R">+  <description>Resistor 22Ω 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="22Ω" constant="no"/><attribute name="MPN" value="CR0402-FX-22R0GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-22R0GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-33R" prefix="R">+  <description>Resistor 33Ω 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="33Ω" constant="no"/><attribute name="MPN" value="CR0402-FX-33R0GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-33R0GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-47R" prefix="R">+  <description>Resistor 47Ω 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="47Ω" constant="no"/><attribute name="MPN" value="CR0402-FX-47R0GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-47R0GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-68R" prefix="R">+  <description>Resistor 68Ω 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="68Ω" constant="no"/><attribute name="MPN" value="CR0402-FX-68R0GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-68R0GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-100R" prefix="R">+  <description>Resistor 100Ω 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="100Ω" constant="no"/><attribute name="MPN" value="CR0402-FX-1000GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-1000GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-150R" prefix="R">+  <description>Resistor 150Ω 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="150Ω" constant="no"/><attribute name="MPN" value="CR0402-FX-1500GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-1500GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-220R" prefix="R">+  <description>Resistor 220Ω 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="220Ω" constant="no"/><attribute name="MPN" value="CR0402-FX-2200GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-2200GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-330R" prefix="R">+  <description>Resistor 330Ω 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="330Ω" constant="no"/><attribute name="MPN" value="CR0402-FX-3300GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-3300GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-470R" prefix="R">+  <description>Resistor 470Ω 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="470Ω" constant="no"/><attribute name="MPN" value="CR0402-FX-4700GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-4700GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-680R" prefix="R">+  <description>Resistor 680Ω 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="680Ω" constant="no"/><attribute name="MPN" value="CR0402-FX-6800GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-6800GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-1K" prefix="R">+  <description>Resistor 1kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-1001GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-1001GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-1K5" prefix="R">+  <description>Resistor 1.5kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1.5kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-1501GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-1501GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-2K2" prefix="R">+  <description>Resistor 2.2kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="2.2kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-2201GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-2201GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-3K3" prefix="R">+  <description>Resistor 3.3kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="3.3kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-3301GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-3301GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-4K7" prefix="R">+  <description>Resistor 4.7kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="4.7kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-4701GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-4701GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-6K8" prefix="R">+  <description>Resistor 6.8kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="6.8kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-6801GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-6801GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-10K" prefix="R">+  <description>Resistor 10kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="10kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-1002GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-1002GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-15K" prefix="R">+  <description>Resistor 15kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="15kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-1502GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-1502GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-22K" prefix="R">+  <description>Resistor 22kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="22kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-2202GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-2202GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-33K" prefix="R">+  <description>Resistor 33kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="33kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-3302GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-3302GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-47K" prefix="R">+  <description>Resistor 47kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="47kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-4702GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-4702GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-68K" prefix="R">+  <description>Resistor 68kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="68kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-6802GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-6802GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-100K" prefix="R">+  <description>Resistor 100kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="100kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-1003GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-1003GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-150K" prefix="R">+  <description>Resistor 150kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="150kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-1503GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-1503GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-220K" prefix="R">+  <description>Resistor 220kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="220kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-2203GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-2203GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-330K" prefix="R">+  <description>Resistor 330kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="330kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-3303GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-3303GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-470K" prefix="R">+  <description>Resistor 470kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="470kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-4703GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-4703GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-680K" prefix="R">+  <description>Resistor 680kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="680kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-6803GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-6803GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-1M" prefix="R">+  <description>Resistor 1MΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1MΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-1004GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-1004GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-0R" prefix="R">+  <description>Resistor 0Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="0Ω" constant="no"/><attribute name="MPN" value="CQ03WAF0000T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ03WAF0000T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-1R" prefix="R">+  <description>Resistor 1Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1Ω" constant="no"/><attribute name="MPN" value="0603WAF100KT5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF100KT5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-1R5" prefix="R">+  <description>Resistor 1.5Ω 0603 - SEI Stackpole</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1.5Ω" constant="no"/><attribute name="MPN" value="RMCF0603FT1R50" constant="no"/><attribute name="MF" value="SEI Stackpole" constant="no"/><attribute name="MOUSER" value="708-RMCF0603FT1R50" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-2R2" prefix="R">+  <description>Resistor 2.2Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="2.2Ω" constant="no"/><attribute name="MPN" value="0603WAF220KT5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF220KT5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-3R3" prefix="R">+  <description>Resistor 3.3Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="3.3Ω" constant="no"/><attribute name="MPN" value="0603WAF330KT5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF330KT5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-4R7" prefix="R">+  <description>Resistor 4.7Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="4.7Ω" constant="no"/><attribute name="MPN" value="0603WAF470KT5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF470KT5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-6R8" prefix="R">+  <description>Resistor 6.8Ω 0603 - SEI Stackpole</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="6.8Ω" constant="no"/><attribute name="MPN" value="RMCF0603FT6R80" constant="no"/><attribute name="MF" value="SEI Stackpole" constant="no"/><attribute name="MOUSER" value="708-RMCF0603FT6R80" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-10R" prefix="R">+  <description>Resistor 10Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="10Ω" constant="no"/><attribute name="MPN" value="0603WAF100JT5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF100JT5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-15R" prefix="R">+  <description>Resistor 15Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="15Ω" constant="no"/><attribute name="MPN" value="0603WAF150JT5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF150JT5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-22R" prefix="R">+  <description>Resistor 22Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="22Ω" constant="no"/><attribute name="MPN" value="0603WAF220JT5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF220JT5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-33R" prefix="R">+  <description>Resistor 33Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="33Ω" constant="no"/><attribute name="MPN" value="0603WAF330JT5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF330JT5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-47R" prefix="R">+  <description>Resistor 47Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="47Ω" constant="no"/><attribute name="MPN" value="0603WAF470JT5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF470JT5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-68R" prefix="R">+  <description>Resistor 68Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="68Ω" constant="no"/><attribute name="MPN" value="0603WAF680JT5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF680JT5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-100R" prefix="R">+  <description>Resistor 100Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="100Ω" constant="no"/><attribute name="MPN" value="CQ03WAF1000T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ03WAF1000T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-150R" prefix="R">+  <description>Resistor 150Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="150Ω" constant="no"/><attribute name="MPN" value="0603SAF1500T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603SAF1500T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-220R" prefix="R">+  <description>Resistor 220Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="220Ω" constant="no"/><attribute name="MPN" value="CQ03WAF2200T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ03WAF2200T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-330R" prefix="R">+  <description>Resistor 330Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="330Ω" constant="no"/><attribute name="MPN" value="0603WAF3300T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF3300T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-470R" prefix="R">+  <description>Resistor 470Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="470Ω" constant="no"/><attribute name="MPN" value="0603WAF4700T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF4700T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-680R" prefix="R">+  <description>Resistor 680Ω 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="680Ω" constant="no"/><attribute name="MPN" value="0603WAF6800T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF6800T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-1K" prefix="R">+  <description>Resistor 1kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1kΩ" constant="no"/><attribute name="MPN" value="CQ03WAF1001T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ03WAF1001T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-1K5" prefix="R">+  <description>Resistor 1.5kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1.5kΩ" constant="no"/><attribute name="MPN" value="0603SAF1501T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603SAF1501T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-2K2" prefix="R">+  <description>Resistor 2.2kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="2.2kΩ" constant="no"/><attribute name="MPN" value="CQ03SAF2201T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ03SAF2201T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-3K3" prefix="R">+  <description>Resistor 3.3kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="3.3kΩ" constant="no"/><attribute name="MPN" value="CQ03SAF3301T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ03SAF3301T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-4K7" prefix="R">+  <description>Resistor 4.7kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="4.7kΩ" constant="no"/><attribute name="MPN" value="CQ03SAF4701T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ03SAF4701T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-6K8" prefix="R">+  <description>Resistor 6.8kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="6.8kΩ" constant="no"/><attribute name="MPN" value="0603WAF6801T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF6801T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-10K" prefix="R">+  <description>Resistor 10kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="10kΩ" constant="no"/><attribute name="MPN" value="CQ03WAF1002T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ03WAF1002T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-15K" prefix="R">+  <description>Resistor 15kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="15kΩ" constant="no"/><attribute name="MPN" value="0603SAF1502T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603SAF1502T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-22K" prefix="R">+  <description>Resistor 22kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="22kΩ" constant="no"/><attribute name="MPN" value="0603WAF2202T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF2202T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-33K" prefix="R">+  <description>Resistor 33kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="33kΩ" constant="no"/><attribute name="MPN" value="CQ03SAF3302T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ03SAF3302T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-47K" prefix="R">+  <description>Resistor 47kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="47kΩ" constant="no"/><attribute name="MPN" value="CQ03SAF4702T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ03SAF4702T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-68K" prefix="R">+  <description>Resistor 68kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="68kΩ" constant="no"/><attribute name="MPN" value="0603WAF6802T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF6802T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-100K" prefix="R">+  <description>Resistor 100kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="100kΩ" constant="no"/><attribute name="MPN" value="CQ03WAF1003T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ03WAF1003T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-150K" prefix="R">+  <description>Resistor 150kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="150kΩ" constant="no"/><attribute name="MPN" value="0603SAF1503T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603SAF1503T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-220K" prefix="R">+  <description>Resistor 220kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="220kΩ" constant="no"/><attribute name="MPN" value="0603WAF2203T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF2203T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-330K" prefix="R">+  <description>Resistor 330kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="330kΩ" constant="no"/><attribute name="MPN" value="0603WAF3303T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF3303T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-470K" prefix="R">+  <description>Resistor 470kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="470kΩ" constant="no"/><attribute name="MPN" value="CQ03WAF4703T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ03WAF4703T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-680K" prefix="R">+  <description>Resistor 680kΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="680kΩ" constant="no"/><attribute name="MPN" value="0603WAF6803T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-0603WAF6803T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0603-1M" prefix="R">+  <description>Resistor 1MΩ 0603 - Royalohm</description>+  <gates>+    <gate name="G$1" symbol="R-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.MK-N_0LHRsCjihDCNieBCA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1MΩ" constant="no"/><attribute name="MPN" value="CQ03SAF1004T5E" constant="no"/><attribute name="MF" value="Royalohm" constant="no"/><attribute name="MOUSER" value="303-CQ03SAF1004T5E" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-10P" prefix="C">+  <description>Multilayer Ceramic Capacitors 10pF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="10pF" constant="no"/><attribute name="MPN" value="MT15N100J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-MT15N100J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-22P" prefix="C">+  <description>Multilayer Ceramic Capacitors 22pF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="22pF" constant="no"/><attribute name="MPN" value="0402N220J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402N220J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-33P" prefix="C">+  <description>Multilayer Ceramic Capacitors 33pF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="33pF" constant="no"/><attribute name="MPN" value="0402N330J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402N330J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-47P" prefix="C">+  <description>Multilayer Ceramic Capacitors 47pF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="47pF" constant="no"/><attribute name="MPN" value="0402N470G500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402N470G500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-100P" prefix="C">+  <description>Multilayer Ceramic Capacitors 100pF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="100pF" constant="no"/><attribute name="MPN" value="0402N101J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402N101J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-220P" prefix="C">+  <description>Multilayer Ceramic Capacitors 220pF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="220pF" constant="no"/><attribute name="MPN" value="0402N221J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402N221J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-1N" prefix="C">+  <description>Multilayer Ceramic Capacitors 1nF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1nF" constant="no"/><attribute name="MPN" value="0402B102J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402B102J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-4N7" prefix="C">+  <description>Multilayer Ceramic Capacitors 4.7nF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="4.7nF" constant="no"/><attribute name="MPN" value="0402B472J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402B472J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-10N" prefix="C">+  <description>Multilayer Ceramic Capacitors 10nF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="10nF" constant="no"/><attribute name="MPN" value="0402B103J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402B103J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-22N" prefix="C">+  <description>Multilayer Ceramic Capacitors 22nF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="22nF" constant="no"/><attribute name="MPN" value="0402B223K250CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402B223K250CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-47N" prefix="C">+  <description>Multilayer Ceramic Capacitors 47nF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="47nF" constant="no"/><attribute name="MPN" value="0402B473J250CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402B473J250CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-100N" prefix="C">+  <description>Multilayer Ceramic Capacitors 100nF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="100nF" constant="no"/><attribute name="MPN" value="0402B104J160CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402B104J160CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-220N" prefix="C">+  <description>Multilayer Ceramic Capacitors 220nF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="220nF" constant="no"/><attribute name="MPN" value="0402B224K160CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402B224K160CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-1U" prefix="C">+  <description>Multilayer Ceramic Capacitors 1uF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1uF" constant="no"/><attribute name="MPN" value="0402X105K250CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402X105K250CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-100P" prefix="C">+  <description>Multilayer Ceramic Capacitors 100pF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="100pF" constant="no"/><attribute name="MPN" value="0603N101J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603N101J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-220P" prefix="C">+  <description>Multilayer Ceramic Capacitors 220pF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="220pF" constant="no"/><attribute name="MPN" value="0603N221J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603N221J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-470P" prefix="C">+  <description>Multilayer Ceramic Capacitors 470pF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="470pF" constant="no"/><attribute name="MPN" value="0603N471J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603N471J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-1N" prefix="C">+  <description>Multilayer Ceramic Capacitors 1nF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1nF" constant="no"/><attribute name="MPN" value="0603N102J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603N102J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-4N7" prefix="C">+  <description>Multilayer Ceramic Capacitors 4.7nF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="4.7nF" constant="no"/><attribute name="MPN" value="0603B472J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603B472J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-10N" prefix="C">+  <description>Multilayer Ceramic Capacitors 10nF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="10nF" constant="no"/><attribute name="MPN" value="0603B103J250CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603B103J250CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-47N" prefix="C">+  <description>Multilayer Ceramic Capacitors 47nF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="47nF" constant="no"/><attribute name="MPN" value="0603B473J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603B473J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-100N" prefix="C">+  <description>Multilayer Ceramic Capacitors 100nF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="100nF" constant="no"/><attribute name="MPN" value="0603B104J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603B104J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-220N" prefix="C">+  <description>Multilayer Ceramic Capacitors 220nF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="220nF" constant="no"/><attribute name="MPN" value="0603B224K250CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603B224K250CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-470N" prefix="C">+  <description>Multilayer Ceramic Capacitors 470nF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="470nF" constant="no"/><attribute name="MPN" value="0603B474M100CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603B474M100CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-1U" prefix="C">+  <description>Multilayer Ceramic Capacitors 1uF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1uF" constant="no"/><attribute name="MPN" value="0603B105K160CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603B105K160CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-2U2" prefix="C">+  <description>Multilayer Ceramic Capacitors 2.2uF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="2.2uF" constant="no"/><attribute name="MPN" value="0603X225K160CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603X225K160CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-4U7" prefix="C">+  <description>Multilayer Ceramic Capacitors 4.7uF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="4.7uF" constant="no"/><attribute name="MPN" value="0603X475K100CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603X475K100CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0603-10U" prefix="C">+  <description>Multilayer Ceramic Capacitors 10uF 0603 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0603">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.4xiOxo_HScOlGwrCwdTusw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="10uF" constant="no"/><attribute name="MPN" value="0603X106K100CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0603X106K100CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0805-100N" prefix="C">+  <description>Multilayer Ceramic Capacitors 100nF 0805 - Samsung Electro-Mechanics</description>+  <gates>+    <gate name="G$1" symbol="C-0805" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0805">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf._exu-nwHSjWYBLSuNRTfWw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="100nF" constant="no"/><attribute name="MPN" value="CL21B104KBCNFNC" constant="no"/><attribute name="MF" value="Samsung Electro-Mechanics" constant="no"/><attribute name="MOUSER" value="187-CL21B104KBCNFNC" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0805-470N" prefix="C">+  <description>Multilayer Ceramic Capacitors 470nF 0805 - Samsung Electro-Mechanics</description>+  <gates>+    <gate name="G$1" symbol="C-0805" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0805">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf._exu-nwHSjWYBLSuNRTfWw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="470nF" constant="no"/><attribute name="MPN" value="CL21B474KBFNNNG" constant="no"/><attribute name="MF" value="Samsung Electro-Mechanics" constant="no"/><attribute name="MOUSER" value="187-CL21B474KBFNNNG" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0805-1U" prefix="C">+  <description>Multilayer Ceramic Capacitors 1uF 0805 - Samsung Electro-Mechanics</description>+  <gates>+    <gate name="G$1" symbol="C-0805" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0805">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf._exu-nwHSjWYBLSuNRTfWw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1uF" constant="no"/><attribute name="MPN" value="CL21B105KBFNNNE" constant="no"/><attribute name="MF" value="Samsung Electro-Mechanics" constant="no"/><attribute name="MOUSER" value="187-CL21B105KBFNNNE" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0805-2U2" prefix="C">+  <description>Multilayer Ceramic Capacitors 2.2uF 0805 - Samsung Electro-Mechanics</description>+  <gates>+    <gate name="G$1" symbol="C-0805" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0805">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf._exu-nwHSjWYBLSuNRTfWw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="2.2uF" constant="no"/><attribute name="MPN" value="CL21A225KAFNNNG" constant="no"/><attribute name="MF" value="Samsung Electro-Mechanics" constant="no"/><attribute name="MOUSER" value="187-CL21A225KAFNNNG" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0805-4U7" prefix="C">+  <description>Multilayer Ceramic Capacitors 4.7uF 0805 - Samsung Electro-Mechanics</description>+  <gates>+    <gate name="G$1" symbol="C-0805" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0805">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf._exu-nwHSjWYBLSuNRTfWw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="4.7uF" constant="no"/><attribute name="MPN" value="CL21A475KAQNNNG" constant="no"/><attribute name="MF" value="Samsung Electro-Mechanics" constant="no"/><attribute name="MOUSER" value="187-CL21A475KAQNNNG" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0805-10U" prefix="C">+  <description>Multilayer Ceramic Capacitors 10uF 0805 - Samsung Electro-Mechanics</description>+  <gates>+    <gate name="G$1" symbol="C-0805" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0805">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf._exu-nwHSjWYBLSuNRTfWw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="10uF" constant="no"/><attribute name="MPN" value="CL21A106KOQNNNG" constant="no"/><attribute name="MF" value="Samsung Electro-Mechanics" constant="no"/><attribute name="MOUSER" value="187-CL21A106KOQNNNG" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0805-22U" prefix="C">+  <description>Multilayer Ceramic Capacitors 22uF 0805 - Samsung Electro-Mechanics</description>+  <gates>+    <gate name="G$1" symbol="C-0805" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0805">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf._exu-nwHSjWYBLSuNRTfWw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="22uF" constant="no"/><attribute name="MPN" value="CL21A226MPQNNNE" constant="no"/><attribute name="MF" value="Samsung Electro-Mechanics" constant="no"/><attribute name="MOUSER" value="187-CL21A226MPQNNNE" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0805-47U" prefix="C">+  <description>Multilayer Ceramic Capacitors 47uF 0805 - Samsung Electro-Mechanics</description>+  <gates>+    <gate name="G$1" symbol="C-0805" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0805">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf._exu-nwHSjWYBLSuNRTfWw?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="47uF" constant="no"/><attribute name="MPN" value="CL21A476MQYNNNE" constant="no"/><attribute name="MF" value="Samsung Electro-Mechanics" constant="no"/><attribute name="MOUSER" value="187-CL21A476MQYNNNE" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="L-470N" prefix="L">+  <description>Inductor 470nH  -</description>+  <gates>+    <gate name="G$1" symbol="L" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="L">+      <connects>+        <connect gate="G$1" pin="1" pad="1"/>+        <connect gate="G$1" pin="2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.toRJ3KRhQ3iFxY1AYlZw6g?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="470nH" constant="no"/><attribute name="MPN" value="" constant="no"/><attribute name="MF" value="" constant="no"/><attribute name="MOUSER" value="" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="L-100N" prefix="L">+  <description>Inductor 100nH  -</description>+  <gates>+    <gate name="G$1" symbol="L" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="L">+      <connects>+        <connect gate="G$1" pin="1" pad="1"/>+        <connect gate="G$1" pin="2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.toRJ3KRhQ3iFxY1AYlZw6g?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="100nH" constant="no"/><attribute name="MPN" value="" constant="no"/><attribute name="MF" value="" constant="no"/><attribute name="MOUSER" value="" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="L-1U" prefix="L">+  <description>Inductor 1uH  -</description>+  <gates>+    <gate name="G$1" symbol="L" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="L">+      <connects>+        <connect gate="G$1" pin="1" pad="1"/>+        <connect gate="G$1" pin="2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.toRJ3KRhQ3iFxY1AYlZw6g?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="1uH" constant="no"/><attribute name="MPN" value="" constant="no"/><attribute name="MF" value="" constant="no"/><attribute name="MOUSER" value="" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="L-10U" prefix="L">+  <description>Inductor 10uH  -</description>+  <gates>+    <gate name="G$1" symbol="L" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="L">+      <connects>+        <connect gate="G$1" pin="1" pad="1"/>+        <connect gate="G$1" pin="2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.toRJ3KRhQ3iFxY1AYlZw6g?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="10uH" constant="no"/><attribute name="MPN" value="" constant="no"/><attribute name="MF" value="" constant="no"/><attribute name="MOUSER" value="" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="L-2U2" prefix="L">+  <description>Inductor 2.2uH  -</description>+  <gates>+    <gate name="G$1" symbol="L" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="L">+      <connects>+        <connect gate="G$1" pin="1" pad="1"/>+        <connect gate="G$1" pin="2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.toRJ3KRhQ3iFxY1AYlZw6g?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="2.2uH" constant="no"/><attribute name="MPN" value="" constant="no"/><attribute name="MF" value="" constant="no"/><attribute name="MOUSER" value="" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="L-4U7" prefix="L">+  <description>Inductor 4.7uH  -</description>+  <gates>+    <gate name="G$1" symbol="L" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="L">+      <connects>+        <connect gate="G$1" pin="1" pad="1"/>+        <connect gate="G$1" pin="2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.toRJ3KRhQ3iFxY1AYlZw6g?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="4.7uH" constant="no"/><attribute name="MPN" value="" constant="no"/><attribute name="MF" value="" constant="no"/><attribute name="MOUSER" value="" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="LED-0402-WHITE" prefix="D">+  <description>LED white 0402 - Inolux</description>+  <gates>+    <gate name="G$1" symbol="LED-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="LED-0402">+      <connects>+        <connect gate="G$1" pin="K" pad="1"/>+        <connect gate="G$1" pin="A" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.3un41Jx6QRC1Nmj1n-LAKg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="white" constant="no"/><attribute name="MPN" value="IN-S42ATUW" constant="no"/><attribute name="MF" value="Inolux" constant="no"/><attribute name="MOUSER" value="=&quot;743-&quot;&amp;I122" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="LED-0402-RED" prefix="D">+  <description>LED red 0402 - Inolux</description>+  <gates>+    <gate name="G$1" symbol="LED-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="LED-0402">+      <connects>+        <connect gate="G$1" pin="K" pad="1"/>+        <connect gate="G$1" pin="A" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.3un41Jx6QRC1Nmj1n-LAKg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="red" constant="no"/><attribute name="MPN" value="IN-S42ATR" constant="no"/><attribute name="MF" value="Inolux" constant="no"/><attribute name="MOUSER" value="=&quot;743-&quot;&amp;I123" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="LED-0402-BLUE" prefix="D">+  <description>LED blue 0402 - Inolux</description>+  <gates>+    <gate name="G$1" symbol="LED-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="LED-0402">+      <connects>+        <connect gate="G$1" pin="K" pad="1"/>+        <connect gate="G$1" pin="A" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.3un41Jx6QRC1Nmj1n-LAKg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="blue" constant="no"/><attribute name="MPN" value="IN-S42ATB" constant="no"/><attribute name="MF" value="Inolux" constant="no"/><attribute name="MOUSER" value="=&quot;743-&quot;&amp;I124" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="LED-0402-GREEN" prefix="D">+  <description>LED green 0402 - Inolux</description>+  <gates>+    <gate name="G$1" symbol="LED-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="LED-0402">+      <connects>+        <connect gate="G$1" pin="K" pad="1"/>+        <connect gate="G$1" pin="A" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.3un41Jx6QRC1Nmj1n-LAKg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="green" constant="no"/><attribute name="MPN" value="IN-S42ATG" constant="no"/><attribute name="MF" value="Inolux" constant="no"/><attribute name="MOUSER" value="=&quot;743-&quot;&amp;I125" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="LED-0402-AMBER" prefix="D">+  <description>LED amber 0402 - Inolux</description>+  <gates>+    <gate name="G$1" symbol="LED-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="LED-0402">+      <connects>+        <connect gate="G$1" pin="K" pad="1"/>+        <connect gate="G$1" pin="A" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.3un41Jx6QRC1Nmj1n-LAKg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="amber" constant="no"/><attribute name="MPN" value="IN-S42ATA" constant="no"/><attribute name="MF" value="Inolux" constant="no"/><attribute name="MOUSER" value="=&quot;743-&quot;&amp;I126" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="LED-0603-WHITE" prefix="D">+  <description>LED white 0603 - Inolux</description>+  <gates>+    <gate name="G$1" symbol="LED-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="LED-0603">+      <connects>+        <connect gate="G$1" pin="K" pad="1"/>+        <connect gate="G$1" pin="A" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.gsqgGNviRjuEu9Y0XXoHgA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="white" constant="no"/><attribute name="MPN" value="IN-S63BT5UW" constant="no"/><attribute name="MF" value="Inolux" constant="no"/><attribute name="MOUSER" value="=&quot;743-&quot;&amp;I127" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="LED-0603-RED" prefix="D">+  <description>LED red 0603 - Inolux</description>+  <gates>+    <gate name="G$1" symbol="LED-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="LED-0603">+      <connects>+        <connect gate="G$1" pin="K" pad="1"/>+        <connect gate="G$1" pin="A" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.gsqgGNviRjuEu9Y0XXoHgA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="red" constant="no"/><attribute name="MPN" value="IN-S63BTR" constant="no"/><attribute name="MF" value="Inolux" constant="no"/><attribute name="MOUSER" value="=&quot;743-&quot;&amp;I128" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="LED-0603-BLUE" prefix="D">+  <description>LED blue 0603 - Inolux</description>+  <gates>+    <gate name="G$1" symbol="LED-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="LED-0603">+      <connects>+        <connect gate="G$1" pin="K" pad="1"/>+        <connect gate="G$1" pin="A" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.gsqgGNviRjuEu9Y0XXoHgA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="blue" constant="no"/><attribute name="MPN" value="IN-S63BT5B" constant="no"/><attribute name="MF" value="Inolux" constant="no"/><attribute name="MOUSER" value="=&quot;743-&quot;&amp;I129" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="LED-0603-GREEN" prefix="D">+  <description>LED green 0603 - Inolux</description>+  <gates>+    <gate name="G$1" symbol="LED-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="LED-0603">+      <connects>+        <connect gate="G$1" pin="K" pad="1"/>+        <connect gate="G$1" pin="A" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.gsqgGNviRjuEu9Y0XXoHgA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="green" constant="no"/><attribute name="MPN" value="IN-S63BTG" constant="no"/><attribute name="MF" value="Inolux" constant="no"/><attribute name="MOUSER" value="=&quot;743-&quot;&amp;I130" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="LED-0603-AMBER" prefix="D">+  <description>LED amber 0603 - Inolux</description>+  <gates>+    <gate name="G$1" symbol="LED-0603" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="LED-0603">+      <connects>+        <connect gate="G$1" pin="K" pad="1"/>+        <connect gate="G$1" pin="A" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.gsqgGNviRjuEu9Y0XXoHgA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="amber" constant="no"/><attribute name="MPN" value="IN-S63BTA" constant="no"/><attribute name="MF" value="Inolux" constant="no"/><attribute name="MOUSER" value="=&quot;743-&quot;&amp;I131" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="LED-2020-WS2812" prefix="D">+  <description>LED WS2812 2020-metric - World Semi</description>+  <gates>+    <gate name="G$1" symbol="LED-2020" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="LED-2020">+      <connects>+        <connect gate="G$1" pin="DOUT" pad="2"/>+        <connect gate="G$1" pin="DIN" pad="4"/>+        <connect gate="G$1" pin="VSS" pad="3"/>+        <connect gate="G$1" pin="VDD" pad="1"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.f1DMoARJRDKHbJRzdxrdYA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="WS2812" constant="no"/><attribute name="MPN" value="WS2812B-2020" constant="no"/><attribute name="MF" value="World Semi" constant="no"/><attribute name="MOUSER" value="n/a" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="FB-0402-47R" prefix="L">+  <description>Ferrite Bead 47 Ω @ 100 MHz 0402 - Murata</description>+  <gates>+    <gate name="G$1" symbol="FB-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="FB-0402">+      <connects>+        <connect gate="G$1" pin="1" pad="1"/>+        <connect gate="G$1" pin="2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.wLUyrxbNTz2S2zho93PcoA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="47 Ω @ 100 MHz" constant="no"/><attribute name="MPN" value="BLM15BA470SN1D" constant="no"/><attribute name="MF" value="Murata" constant="no"/><attribute name="MOUSER" value="81-BLM15BA470SN1D" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="FB-0402-600R" prefix="L">+  <description>Ferrite Bead 600 Ω @ 100 MHz 0402 - Murata</description>+  <gates>+    <gate name="G$1" symbol="FB-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="FB-0402">+      <connects>+        <connect gate="G$1" pin="1" pad="1"/>+        <connect gate="G$1" pin="2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.wLUyrxbNTz2S2zho93PcoA?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="600 Ω @ 100 MHz" constant="no"/><attribute name="MPN" value="BLM15AX601SN1D" constant="no"/><attribute name="MF" value="Murata" constant="no"/><attribute name="MOUSER" value="81-BLM15AX601SN1D" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-2K" prefix="R">+  <description>Resistor 2kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="2kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-2001GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-2001GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-120R" prefix="R">+  <description>Resistor 120Ω 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="120Ω" constant="no"/><attribute name="MPN" value="CR0402-FX-1200GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-1200GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="R-0402-5K6" prefix="R">+  <description>Resistor 5.6kΩ 0402 - Bourns</description>+  <gates>+    <gate name="G$1" symbol="R-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="R-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.KHK5vcsmQke6VRq1R2AgTg?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="5.6kΩ" constant="no"/><attribute name="MPN" value="CR0402-FX-5601GLF" constant="no"/><attribute name="MF" value="Bourns" constant="no"/><attribute name="MOUSER" value="652-CR0402FX-5601GLF" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-68P" prefix="C">+  <description>Multilayer Ceramic Capacitors 68pF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="68pF" constant="no"/><attribute name="MPN" value="0402N680J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402N680J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-330P" prefix="C">+  <description>Multilayer Ceramic Capacitors 330pF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="330pF" constant="no"/><attribute name="MPN" value="0402N331J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402N331J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-470P" prefix="C">+  <description>Multilayer Ceramic Capacitors 470pF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="470pF" constant="no"/><attribute name="MPN" value="0402B471J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402B471J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+<deviceset name="C-0402-3N3" prefix="C">+  <description>Multilayer Ceramic Capacitors 3.3nF 0402 - Walsin</description>+  <gates>+    <gate name="G$1" symbol="C-0402" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="C-0402">+      <connects>+        <connect gate="G$1" pin="~" pad="1"/>+        <connect gate="G$1" pin="~@2" pad="2"/>+      </connects>+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.em19qek7T0Wax4FRpamo4w?version=1"/></package3dinstances>+      <technologies>+        <technology name=""><attribute name="VALUE" value="3.3nF" constant="no"/><attribute name="MPN" value="0402B332J500CT" constant="no"/><attribute name="MF" value="Walsin" constant="no"/><attribute name="MOUSER" value="791-0402B332J500CT" constant="no"/></technology>+      </technologies>+    </device>+  </devices>+</deviceset>+</devicesets>+</library>+</drawing>+</eagle>\ No newline at end of file
BRIDGE_VERSIONadded+1
@@ -0,0 +1 @@+1.8.3\ No newline at end of file
LICENSEadded+21
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2026 Adom Industries, Inc. and contributors++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
NEXT-SESSION-bq25792-viewer.mdadded+76
@@ -0,0 +1,76 @@+# HANDOFF: BQ25792 charger viewer — Fusion-source rebuild (do this FIRST next session)++Live page: https://wiki.adom.inc/adom/bq25792-charger  (readme viewer at v0.1.49)+Working dir: /tmp/bq25792-charger  (readme.html + the group GLB PNGs)++## The pivot John demanded (2026-07-16)++STOP reverse-engineering the flattened/join-merged GLB. Build the viewer's layers from+FUSION SOURCE TRUTH instead. The merged GLB is why components can't be identified and why+the inner copper is faked from gerber raster PNGs.++## Decisions already locked (do NOT re-ask)++- Machine-pins layer = ALL 14 (MP1..MP14), by NAME from Fusion. Anchored, never animated.+- Everything else (C*/R*/U*/L*/J*/D*/Q*...) -> "Components" layer (the animated top layer).+- Inner copper L2/L15 must be REAL VECTORS from Fusion, same PBR copper material as outer,+  NOT gerber PNG planes.+- Fusion is NOT open on the board -> must open by URN first (Main project, doc v222).++## PROGRESS 2026-07-16 (started, then hit context limit + relay flap)++- ADOMGPU: Fusion NOT installed (fusion_readiness). Use AdomLapper instead.+- AdomLapper: Fusion INSTALLED. `fusion_start` SUCCEEDED (addinReady:true). Active doc = "Untitled"+  (board NOT open yet).+- BLOCKER hit: locating the board in the cloud. `fusion_search_cloud_files {query:"BQ25792"}` and+  {query:"BQ",project:"Main"} both returned 0 files (searched only 1 folder — search scope/project+  arg may be wrong). `fusion_walk_cloud_tree` then returned a stale "call fusion_start" hint = relay+  FLAP (Fusion was running). Retry the walk/search after re-confirming fusion_get_app_state; may+  need the exact project name or a cached URN. The .f3d is ALSO already on the wiki page+  (bq25792-charger.f3d in /tmp/bq25792-charger) — could fusion_aps_upload + open that, or open the+  local f3d directly, instead of hunting the cloud original.++## Exact plan (one source pass fixes BOTH components + copper)++1. On AdomLapper: Fusion already startable. Open BQ25792 — either find the cloud URN (retry+   search/walk after app_state re-confirm) OR just open the local .f3d from the wiki page+   (/tmp/bq25792-charger/bq25792-charger.f3d) which is the same v222 design.+2. `fusion_run_modeling_script` — ONE script that:+   a. Walks the occurrence tree; export each occurrence's mesh tagged by designator.+      MP1..MP14 -> machine-pins group; all others -> components group.+   b. Pulls each copper layer's polygons (top/L2/L15/bottom) as geometry.+      Two options: (i) the Electronics board API trace/polygon geometry, or+      (ii) `fusion_export_dxf` per copper layer (DXF = vectors) then triangulate closed polys.+      NOTE the earlier gerber2glb bug: gerber coords are MILLI-UNITS; I mis-scaled (÷1e6 vs+      the real viewBox units) which blew the mesh up to a speck. DXF avoids that; if reusing+      gerber2glb (/tmp/gerber2glb.mjs), fix the unit scale against the viewBox first.+3. Rebuild the viewer layers from that source data. The engine already works — only the layer+   SOURCES change. Keep: cascade-up animation, layers panel (live z + visibility + hover-+   highlight), realtime order check, Play/Pause + scrub (2-min resume), draggable floaties,+   Click-pivot toggle (camera.setClickToSetRotationPoint), Ground toggle, deterministic+   framing (radius 0.115 at board center 25.2,13.2,18mm — computed diag blows up, don't use it).+4. Verify on AdomLapper (session bqview, hwnd in /tmp/bqview_hwnd.txt), flash, show John.++## What already works at v0.1.49 (don't regress)++Native Adom Babylon9 viewer + ViewCube; cascading UPWARD explode (nothing below ground);+layers panel; order check; Play/Pause + scrub; Click-pivot + Ground toggles; Fullscreen;+draggable floaties; unified PBR copper (albedo 0.95,0.60,0.42 / metallic 1 / roughness 0.28 /+envIntensity 1.2); transparent ground (alpha 0.2) + every-frame shadow refresh.++## Key infra facts++- readme CSP: connect-src 'none' -> models ride as lossless PNGs in the repo (bytes in RGB,+  4-byte LE length header), decoded via CORS canvas (loadPngBytes). ~4-5MB readme cap.+- Storage shim in <head> (sandboxed docs throw on localStorage -> aborts the bundle's rig).+- Blob->dataURI shim in the module (img-src has no blob:).+- Group GLBs: optimize with --instance false; do NOT quantize (bounds lie); images -> data URIs.+- Publish loop: repo push + `adom-wiki pkg publish --org adom --public -y`, bump version in+  BOTH package.json and page.json.+- Platform asks on adom/wiki #47 (CSP, size cap, /blob content-types, iframe height,+  allowfullscreen, deployed-bundle sandbox rig, native exploded-animation mode).++## Skill draft (private, NOT yet shipped — too hacky per John)++/home/adom/project/wiki-readme-3d-skill/SKILL.md — full recipe. Ship to the wiki skillpack+ONLY once the Fusion-source approach replaces the hacks.
SKILL.mdadded+297
@@ -0,0 +1,297 @@+---+name: adom-desktop-fusion+public: true+description: "Launch and drive Fusion 360 on the user's laptop from this container via the adom-desktop CLI. Includes FAST cloud-file search via APS (Autodesk Platform Services) — search/browse/open the team's Fusion cloud designs in seconds (set up once per company, each user signs in once, never charged). Plus open .f3d/.f3z designs, open cloud files, close documents, dismiss recovery dialogs, capture Fusion window screenshots, send keys + click, run the add-in (STEP/GLB/.lbr import-export, BOM/parameters). Trigger words: fusion, Fusion 360, fast cloud search, fusion_aps_search, search fusion files, find a design, browse cloud files, fusion_aps_open, aps, open fusion, launch fusion, open design, f3d, f3z, import STEP, export STEP, export GLB, export lbr, Fusion electronics, Fusion PCB, BOM from Fusion, Fusion parameters, Fusion API, dismiss recovery, Fusion screenshot, fusion_click, fusion_send_key, fusion bridge, close fusion."+---++# adom-desktop — Fusion 360 bridge++All commands dispatch to the Fusion Python bridge. From this container:++```bash+adom-desktop fusion_<action> '<json_args>'+```++The leading `fusion_` routes to the Fusion plugin; `<action>` is the plugin-side name.++## FIRST-TIME / COLD-START — read before you panic++A fresh laptop may not have Fusion running (or may run a stale add-in). That is EXPECTED, not defeat.+Branch on the stable `errorCode`, never the prose:++| response (`errorCode`) | what it means | what you do |+|---|---|---|+| `ready:true` (fusion_readiness) | Fusion up + add-in current | drive |+| `running:false` / `fusion_not_running` | installed, not launched | `fusion_start` (returns when the add-in is ready, or `stillLaunching` on a slow first launch) |+| `stillLaunching:true` (fusion_start) | first launch, add-in not up yet (can take 2-4 min) | do NOT re-call `fusion_start`; POLL `fusion_readiness` every ~10s until `ready:true` |+| `installed:false` / `host_app_not_installed` (AD >=1.9.79, + a `hostApp` field) | no Fusion host app | OFFER to install, then **`fusion_install_fusion`** (no shell approval; elevation-aware, streams the free trial) -> poll `fusion_readiness` (`installing:true`) until `installed:true` -> `fusion_start`. Details: [fusion-onboarding](skills/fusion-onboarding/SKILL.md) |+| `needsSignin:true` (`fusion_start` **and** `fusion_readiness`) | Fusion is running but stuck at the first-run Autodesk sign-in (main UI blocked, add-in can't serve, so `ready:false`) | AUTOMATE it (proven sequence, see [fusion-onboarding](skills/fusion-onboarding/SKILL.md)): (1) clear STALE `signin.autodesk.com` tabs (a dead tab = expired code = "Sign-in request expired"); (2) `desktop_ui_click` "Retry browser sign-in" / "Sign In" for ONE fresh request; (3) click "Open Product" with **`desktop_click` (SendInput=isTrusted)** — `desktop_ui_click` (UIA) does NOT fire the protocol; (4) on the in-page "open Autodesk Identity Manager?" overlay (NOT an owned popup) tick "Always allow" + "Open" via `desktop_click`, FAST; (5) poll `fusion_readiness`. `nbrowser` (CDP) can do 3-4 headlessly if it's on the SAME browser window. NEVER auto-enter password/2FA. To ask the user, `notify_user` works directly (AD ≥1.9.84); add a cross-AD `target` if you're on a VM |+| `addinStale:true` / `addin_stale` | Fusion runs an OLD add-in that never re-synced (silent-failure risk) | `fusion_stop` then `fusion_start` — the bridge re-syncs the add-in from cache on start (Fusion must be CLOSED) |+| `bridge_restarting` + `stillRunning:true` (AD ≥1.9.77) | the bridge is respawning after a `bridge_install` | NEVER a not-installed/fatal signal: poll `fusion_readiness` until `ready:true`, then retry. Read-only verbs (`fusion_readiness`/`fusion_describe`/`fusion_get_app_state`) forward straight through even mid-respawn — no sleep-and-recheck hacks needed |+| `blockingDialogs:[…]` | a modal is blocking the add-in | dismiss in the BACKGROUND, then the op auto-resumes |++**Runtime note:** AD **provisions Python itself** (a portable no-UAC 3.12.13 runtime if none is on PATH — the bridge never bootstraps its own; check AD's `runtimes` verb). You never install Python.++## The 8 conventions (from the Bridge SDK)++1. **Poll readiness, don't launch blindly.** `fusion_readiness` (or AD's `bridge_readiness`) is read-only — it reports `installed`/`running`/`ready`/`addinStale` WITHOUT launching anything. Loop: readiness → act on the row above → drive.+2. **`fusion_readiness` is the standardized cold-start probe.** (Fusion is a detected HOST APP with no heavy download, so there's no `prewarm` step — readiness is the whole gate.)+3. **Core verbs live in the table below; `fusion_describe '{}'` is the full machine-readable catalog.** Read the table to act fast; hit `describe` for completeness — don't guess a verb.+4. **Background by default — automate first, NOTIFY only at a true wall.** This bridge drives the AI's workspace, not the user's screen: dismiss dialogs in the BACKGROUND (`fusion_close_window`, never `fusion_send_key`/Escape, which steals focus). AUTOMATE sign-in / dialogs yourself (see the proven sign-in sequence in [fusion-onboarding](skills/fusion-onboarding/SKILL.md)); reserve an AD **`notify_user`** for something only the user can do — a **UAC/elevation** prompt, a license accept, a **2FA/password** step you must not auto-fill, or a licensing **DECISION** that risks their other machine. **`notify_user` works directly over the bridge's direct API (AD ≥1.9.84) — call it, don't relay a payload for the AI to send.** When this bridge runs UNATTENDED (e.g. on a VM) and the user is elsewhere, add a cross-AD **`target`** (a peer clientName from the `targets` verb, or `"all"`) so the toast lands where they are. Only foreground Fusion to SHOW the user something. See [fusion-driving](skills/fusion-driving/SKILL.md) and [fusion-onboarding](skills/fusion-onboarding/SKILL.md).+5. **`ok:true` is not enough — verify.** A long op that "times out" at ~60s is usually STILL RUNNING server-side (the relay caps the request, not the work). Verify by artifacts (the saved file / a screenshot / `fusion_get_app_state`), don't blindly retry.+6. **Reuse the running Fusion — and when a restart IS needed, YOU do it, never the user.** Fusion is a singleton: `fusion_readiness` before `fusion_start`; if `ready`, just drive. But a stale/missing add-in or a wedged session needs a restart, and that is YOUR job — `fusion_stop` then `fusion_start`. NEVER tell the user "restart Fusion" / "enable the add-in in UTILITIES" — doing it for them is the entire point of this bridge. (Add-in installs land in ALL Fusion add-in dirs — 2025+ Fusion scans `%APPDATA%\Autodesk\FusionAddins`, older builds use `...\Autodesk Fusion[ 360]\API\AddIns` — so a restart always picks it up.)+7. **Surface `_hint` verbatim + branch on `errorCode`.** Every verb returns an actionable `_hint`; relay it to the user unchanged and key your logic off the stable `errorCode`, not the prose.+8. **Never write files to a shared cloud ROOT.** Uploads default to an `Adom AI Workspace` folder; see [fusion-cloud-hygiene](skills/fusion-cloud-hygiene/SKILL.md).++## [!] Electronics PCBs: ALWAYS open the PROJECT file (never the schematic / board / 3D)++A Fusion electronics design is NOT one file. It is a parent/child chain of FOUR files, each a+different `productType`:++```+PROJECT        EcadDesignProductType     <-- OPEN THIS ONE, ALWAYS+  |- schematic   SchematicProductType+  |- board/.brd  BoardProductType+  |- 3D PCB      DesignProductType        (generated from the .brd - the LEAF; opening it gives NO editable board)+```++- **Open the PROJECT** (`EcadDesignProductType`) with `fusion_open_cloud_file` / `fusion_open_by_urn`.+  Fusion then brings up its schematic + board as children; move between them with the schematic view,+  `fusion_show_2d_board`, and `fusion_show_3d_board`.+- **NEVER open the schematic, the .brd, or the 3D file directly** to "get the board." You get an+  isolated/empty view and waste time trying to derive a 2D board from the 3D. The 3D is the LEAF,+  generated FROM the .brd - it is not the board, and you cannot pull a board out of it.+- Same-named copies in OTHER projects (e.g. a drone assembly) are usually 3D-model derivatives+  (`DesignProductType`), NOT the project. Don't open those.+- `fusion_open_cloud_file` / `fusion_open_by_urn` REPRIMAND you in the response `_hint` when you open+  a child file instead of the project - read it and re-open the `EcadDesignProductType` project.++## ⚡ Fast cloud search (APS) — READ THIS FIRST for any "find/search/open a cloud design" task++To search the team's Fusion cloud files, use **`fusion_aps_search`**, NOT the legacy+`fusion_search_cloud_files` (which walks folders one-by-one and takes 30+ MINUTES). APS hits+Autodesk's **server-side index** → results in **seconds**, and works with Fusion closed.++| Verb | Does |+|---|---|+| `fusion_aps_search {query, projectId?, limit?}` | Fast name search across the whole team hub; newest-first; shows each file's project. |+| `fusion_aps_browse {} / {projectId} / {projectId,folderId}` | Browse hubs→projects→folders→files (cloud explorer, no Fusion). |+| `fusion_aps_open {query}` | Search + open the best match in Fusion (opens by exact URN — works for nested files). Returns immediately; the open finishes in the background — poll `fusion_get_app_state` (or pass `{wait:true}`). |+| `fusion_aps_recent {limit?}` | Most-recently-modified designs across the hub, newest-first. |+| `fusion_aps_file_info {query}` | Version history for a file — count, who/when last modified, size. |+| `fusion_aps_status {}` | configured? signedIn? token live? + never-charge usage meter. **Call this first** — its `_hint` tells you the next step. |+| `fusion_aps_signin {}` | One-time per user: opens Autodesk consent, captures the token. |+| `fusion_aps_set_client_id {clientId}` | Set the org's APS Client ID. |++**Auth model (important): set up ONCE per company, each user signs in once.** An admin registers a free APS app for the org one time (the AI drives the whole setup — see the `fusion-aps-signin` skill) → a **Client ID** (a public PKCE id, no secret, safe to share within the org). Then every teammate just runs `fusion_aps_signin` once with their own Autodesk login — **no plan, no card, no setup** for them. It's **per-organization** (each company runs its own setup; don't ship one global Client ID). **Nobody is ever charged** — the card is identity-verification only, and the bridge is free-endpoint-only + usage-capped.++If `fusion_aps_status` says not configured/signed in, follow its `_hint`. Full why + step-by-step setup: the bundled **`fusion-aps-search`** and **`fusion-aps-signin`** skills.++## ⛔ "Expired subscription — Read Only" / trial / personal Fusion — what it does NOT block++**An expired / "Read Only" / personal-use Fusion can OPEN, VIEW, and BROWSE files just fine.**+Autodesk keeps the account in **Basic Access for 365 days** after a subscription lapses. So in+read-only Fusion you CAN: **open cloud designs, view/inspect them, browse the Data Panel, and run+APS search** — everything this bridge does for *reading* works.++Read-only ONLY blocks **save, export, modify, and creating new designs** (the Save/Export buttons+are dimmed). So:++- ⛔ **NEVER tell the user an `open` / `view` / `search` failed "because the Fusion subscription+  is expired / read-only."** That is FALSE and confuses users (it's been said wrongly many times).+  If `fusion_aps_open` / `fusion_open_cloud_file` hangs or fails, it is a **code / approach+  problem in the open path** (URN resolution, the Electronics design picker, a slow assembly+  download, a stuck main thread) — debug/fix THAT, not the license. Try harder; don't blame the+  subscription.+- ✅ The ONLY place read-only is a legitimate explanation is **save / export** — e.g.+  `fusion_export_*` may be blocked (Save/Export dimmed). There, "renew the subscription" is valid.++(Source: Autodesk — "Term has Expired or Usage Limits Exceeded"; data stays in Basic Access ~365 days.)++## Commands (core bridge)++| CLI form | Action | Purpose | Key args |+|---|---|---|---|+| `fusion_start` / `fusion_launch` | `start` / `launch` | Launch Fusion 360 (handles webdeploy glob, waits for bridge, dismisses startup picker) | — |+| `fusion_open_design` | `open_design` | Open a local `.f3d` / `.f3z` design file | `path` |+| `fusion_open_cloud_file` | `open_cloud_file` | Open a design from the user's Fusion cloud | `project`, `path` |+| `fusion_close_document` | `close_document` | Close the active document | — |+| `fusion_close_window` | `close_window` | Close a specific Fusion window by HWND | `hwnd` |+| `fusion_close` | `close` | Close Fusion 360 entirely | — |+| `fusion_dismiss_recovery` | `dismiss_recovery` | Dismiss the "recover unsaved work" dialog | — |+| `fusion_relocate_recovery` | `relocate_recovery` | Move recovery dialog offscreen (for recording) | — |+| `fusion_window_info` | `window_info` | Enumerate Fusion windows (HWND, title, bounds) | — |+| `fusion_screenshot_fusion` | `screenshot_fusion` | Screenshot the main Fusion window | — |+| `fusion_screenshot_all` | `screenshot_all` | Screenshot every Fusion window | — |+| `fusion_click_fusion` | `click_fusion` | Click at (x, y) in the Fusion main window | `x`, `y` |+| `fusion_send_key` | `send_key` | Send a keyboard shortcut to Fusion | `hwnd`, `key` |+| `fusion_addin_status` | `addin_status` | Report whether the in-process Adom add-in is loaded + healthy | — |+| `fusion_generate_package` | `generate_package` | Generate an IPC package via Fusion's built-in EPG (~50 families) + raised-WHITE marking (longest-axis, measured 10% margin, multi-line MPN+variant) + colored STEP + sidecar manifest - in ONE call | `type`, `params` (mm), `etch`, `etchStyle`, `outputStep` |+| `fusion_set_preference` | `set_preference` | Set appearance/navigation prefs LIVE (no restart): `theme` (light/darkblue/darkgray/classic/device/dark), `invertScrollZoom`, `orbitScheme` (fusion360/alias/inventor/solidworks/tinkercad/powermill), `modelingOrientation` (yup/zup), `gestureNav`, `cameraPivot`, `lengthUnit` (mm/cm/m/in/ft). Per-key result in `applied`; some themes aren't in every build (falls back) | any of the keys |+| `fusion_get_preferences` | `get_preferences` | Read current appearance/navigation prefs as the friendly values `set_preference` accepts | — |++## Extended commands via the in-process add-in++If the Adom add-in is installed (`cd ~/project/adom-desktop/plugins/fusion360 && python install_addin.py` on the laptop), Fusion 360 exposes an additional API over its own ports. Typical extra commands proxied through the bridge:++- `fusion_import_step` — import a STEP file into the active document+- `fusion_export_step` — export active body/occurrence to STEP+- `fusion_export_glb` — export to GLB (used by the 3D viewer)+- `fusion_export_lbr` — export an Eagle library (used by the Eagle workflow)+- `fusion_open_lbr` / `fusion_open_symbol` — open symbol libraries+- `fusion_command` — generic `{"command": "<fusion_api_name>", "args": {...}}` pass-through for any Fusion API call+- `fusion_list_cloud_projects`, `fusion_list_cloud_files`, `fusion_walk_cloud_tree`, `fusion_search_cloud_files`, `fusion_open_cloud_file`, `fusion_export_cloud_file` — Autodesk cloud Data API operations++**Opening multi-design electronics files — pass `fileExtension`.** A Fusion electronics data file that links to multiple designs (common for boards with variants) makes `fusion_open_cloud_file` pop Fusion's native **"Select Electronics Design File" picker** — a CEF/Chromium modal whose list is **not keyboard- or Win32-navigable** (and screen-coord clicks are unreliable on multi-monitor/HiDPI), so it **can't be resolved headlessly**. Avoid it by opening the specific file directly: `fusion_open_cloud_file {"fileName":"<name>","fileExtension":"fbrd", ...}` (the `.fbrd` board lands straight in PCB Editor — live-confirmed). Opening the bare name or the `.fprj` project triggers the picker. If a picker still appears, `_diagnose_addin_timeout`/`blockingDialogs` will classify it (see below).++### Blocking-dialog awareness++Several Fusion modals (the multi-link "Select Electronics Design File" picker, "Fusion needs to update", Document Recovery, "Save changes?") block the add-in's main thread. The bridge now **classifies them by title** and, on a blocked command, returns `blockingDialogs: [{hwnd, title, category, resolution}]` with the precise cause + fix — instead of a misleading "add-in not responding / may have crashed". So a blocked open tells you *which* modal is up and how to clear it.++Resolution notes:+- **Multi-link picker** is a **CEF/web modal whose list is NOT keyboard- or Win32-navigable** (SendInput reaches only the native Cancel/OK; screen-coord clicks are unreliable on multi-monitor/HiDPI). It currently **must be resolved on the desktop**. *Headless fix tracked separately:* have the add-in open the specific linked design via the Fusion API, avoiding the picker entirely.+- **Update nag** is reported, not auto-dismissed (auto-confirming could start an update mid-run) — clear it on the desktop; doing so also commonly resolves recurring add-in crashes (host/add-in version drift).+- **Recovery** prompts: `fusion_dismiss_recovery` / `fusion_relocate_recovery`.++Check `fusion_addin_status` first — if the add-in isn't loaded, these will fail with a `_hint` pointing at the install script.++## Cloud search — defensive contract (add-in v1.0.2+)++`fusion_search_cloud_files` is the most-used long-running verb. Its v1.0.2 behavior is engineered specifically so the AI never misreports a failed search as "file not found":++| You read in the response | Mean |+|---|---|+| `searchComplete: true` + `totalFound: 0` | **Confirmed negative.** No match in the searched scope. |+| `searchComplete: true` + `totalFound: N` | All matches returned. |+| `searchComplete: false` (any reason) | **Search stopped early.** May or may not be more matches. Do NOT say "not found" to the user. Re-run with broader caps OR narrower `folderPath`. |++`searchComplete` is `true` ONLY when every one of these is clean: not `folderLimitReached`, not result-`truncated`, not `searchTimedOut`, `foldersSkipped == 0`, `filesSkipped == 0`. Five conditions, all five must pass.++### Performance + the slow-search etiquette++`fusion_search_cloud_files` runs at ~1 folder/sec because Autodesk's free Fusion 360 Python API has no indexed search endpoint — it walks the cloud Data API one folder at a time (30+ min on a real hub). **⚠️ Prefer `fusion_aps_search` instead** (see the APS section at the top) — it uses Autodesk Platform Services' server-side index and returns in **seconds**. This legacy walk verb remains only as a fallback for when APS isn't set up; if a user is hitting slow searches, set up APS (`fusion_aps_status` → its `_hint`) rather than tuning the walk.++**Before firing a broad search**, ask the user which subfolder is likely. Naming a folder like "Molecules" cuts 5-40 min searches down to ~10s. The verb's response includes a `costAnalysis` block (`foldersPerSecond`, `estimatedSecondsPer100Folders`) so the AI can budget realistically.++### Streaming progress++For interactive sessions, wrap long searches in `watch` so the AI gets one JSON-line progress event per `interval` seconds:++```bash+adom-desktop watch '{+  "command": "fusion_search_cloud_files",+  "args": {+    "query": "cosmiic",+    "projectName": "Main",+    "folderPath": "Molecules",+    "recursive": true,+    "maxFolders": 300,+    "maxDepth": 10,+    "searchTimeout": 340,+    "timeout": 400+  },+  "interval": 3+}'+```++Output:+```+{"event":"started", ...}+{"event":"progress", "foldersVisited": 12, "filesFound": 1, "elapsedSeconds": 15.1, "currentFolder": "Molecules/COSMIIC", ...}+{"event":"progress", "foldersVisited": 173, "filesFound": 3, "elapsedSeconds": 168.3, ...}+{"event":"complete", "result": {... full response with searchComplete:true ...}}+```++The `watch` wrapper composes with the `Monitor` tool — each stdout line becomes a notification.++### Args (no hard upper caps in v1.0.2+)++| Arg | Default | Notes |+|---|---|---|+| `query` | (required) | Substring of file name. **Case-insensitive both directions.** |+| `projectName` | active | Cloud project name. |+| `folderPath` | project root | Starting subfolder. **NARROW HERE — biggest perf lever.** |+| `recursive` | `false` | Descend into subfolders. |+| `maxDepth` | 2 | Recursion depth cap. |+| `maxFolders` | 10 | Folder-visit cap. |+| `maxResults` | 20 | Result cap. |+| `folderTimeout` | 30s | Per-folder cloud-API timeout. Bridge skips slow folders. |+| `searchTimeout` | 120s | Overall wall-clock timeout. Set 300+ for big walks. |+| `timeout` | 620s | HTTP envelope timeout (CLI+direct API). Bump if `searchTimeout` > 180. |++Real-world live test: `Main/Molecules` recursive depth-10 cosmiic search hit 173 folders in 168s with `searchComplete:true, totalFound:3, foldersSkipped:0, filesSkipped:0`. Fusion stayed `main_thread: responsive` throughout.++## Quick examples++```bash+# Launch Fusion+adom-desktop fusion_start '{}'++# Open a local design+adom-desktop fusion_open_design '{"path":"C:/designs/board.f3d"}'++# Screenshot all Fusion windows+adom-desktop fusion_screenshot_all '{}'++# Run a Fusion API command (add-in required)+adom-desktop fusion_command '{+  "command":"export_step",+  "args":{"occurrence":"body1","output":"C:/tmp/part.step"}+}'++# Check add-in health+adom-desktop fusion_addin_status '{}'+```++## Error shape++Every failing response includes a `_hint` field. Surface it verbatim when a Fusion command fails.++## Bridge architecture (v1.8.31+) — dynamic ports++Earlier versions used hardcoded port `8773` for the bridge and `8774` for the in-process add-in. **v1.8.31 made the bridge use OS-assigned ephemeral ports.** The add-in port is still 8774 (it's inside Fusion's process and the manifest pins it), but that's an internal detail.++- The CLI (`adom-desktop fusion_*`) routes through adom-desktop's direct API → the bridge's runtime port. No callers need port numbers.+- The add-in v1.0.2 ships a stale-lock watchdog in `http_server.py`: if a command holds the main-thread lock longer than `per_command_timeout + 30s` (e.g. Fusion's native cloud SDK wedges on a slow API call), the watchdog force-releases so subsequent commands work without restarting Fusion. The wedged command is orphaned but no longer blocks everything else.+- The `searchComplete` contract (see above) prevents false-negative reporting on capped/skipped searches. Always check `data.searchComplete` before telling the user "file not found".++## How this bridge is packaged + delivered (3 artifacts)++This bridge is ONE wiki page (`wiki.adom.inc/adom/adom-desktop-fusion-bridge`) that ships **three things**:++1. **The page git repo** — the ONE source of truth (all source, `skills/`, the docs, `page.json`, and the+   bridge manifest). Edit + push here.+2. **The Release zip + the bridge manifest** (`adom-bridge-fusion-manifest.json`) — what **adom-desktop**+   consumes on `bridge_install`: the manifest tells adom-desktop who this bridge is (name, version, the+   Release-zip URL, sha256, size, verb prefixes, health), and it streams that zip into its bridge cache.+3. **The adom-wiki skills pkg** (`adom-wiki pkg install adom/adom-desktop-fusion-bridge`) — **skills only**.+   It deploys these skills into a container's `~/.claude/skills/` so the AI knows how to drive this bridge+   and Fusion.++**Install handshake:** when an AI has adom-desktop install this bridge, adom-desktop installs the Release+AND tells the AI to `adom-wiki pkg install` this pkg — so the container gets all these skills. An AI can+also install the pkg itself; then the skills **auto-update** via the pkg mechanism (the goal). Full detail++ the publish ritual + the hero-relink reminder: the **`fusion-bridge-dev`** skill.++## Related++- **Building component libraries (symbol + footprint + RENDERING 3D):** **`fusion-libraries`** (one part) and **`fusion-multipart-libraries`** (many parts in one `.lbr`, each with real 3D) — the latter's SOLVED recipe is `fusion_make_3d_package` (STEP → orient → f3d → upload → `wip_urn`, hand-written into the library, **no GUI dialogs**). Full tutorial: the **`fusion-multipart-libraries`** skill's `CREATING_BASIC_PARTS_LIBRARIES.md`. Operate Fusion safely with **`fusion-driving`** + **`fusion-cloud-save`**.+- **`fusion-aps-search`** + **`fusion-aps-signin`** — APS fast-search reasoning + the AI-driven one-time setup (bundled in this repo's `skills/`).+- `adom-desktop-kicad` — sibling bridge for KiCad.+- `adom-desktop-direct-api` — the direct API contract that callers route through.+- **Canonical repo:** the wiki page `https://wiki.adom.inc/adom/adom-desktop-fusion-bridge` (+ GitHub backup `adom-inc/adom-desktop-fusion-bridge`). The old `adom-inc/adom-desktop/plugins/fusion360/` is a stale seed.++## Quick demo on first install (sample library included)++The repo ships a ready sample so you can prove the bridge end to end right after installing:+`examples/ADS8588SIPM.fusion.lbr` (a real 4-sided LQFP-64 library) + `examples/ADS8588SIPM.step` (its 3D).++1. Download both from this page's Files tab (or `adom-wiki repo clone`), then stage them onto Windows+   (serve + `Invoke-WebRequest`, since there is no container->Windows push verb).+2. **Import demo:** `fusion_open_lbr {"filePath":"C:/.../ADS8588SIPM.fusion.lbr","verify":true}` -> the+   symbol + 4-sided footprint render in the Electronics Library editor.+3. **3D-attach demo:** `fusion_attach_3d_package {"filePath":"C:/.../ADS8588SIPM.fusion.lbr",+   "modelPath":"C:/.../ADS8588SIPM.step","packageName":"ADS8588SIPM"}` -> click the Save dialog per the+   returned hint -> the real chip binds onto the footprint (Content Manager shows the 3D under the package).++See the **`fusion-libraries`** skill's `MAKING_LIBRARIES.md` for the full walkthrough + screenshots.
VERBS.mdadded+1347
@@ -0,0 +1,1347 @@+# Fusion bridge - verb reference++Every `fusion_*` verb this bridge exposes, generated from the bridge's own self-describe+(`describe.py` / `fusion_describe`) so it never drifts. Call as:++```+adom-desktop fusion_<verb> '<input json>'+```++`input` / `output` below are the SCHEMA (field -> type/notes); `example` is a real input.+`timeoutSeconds` is AD's wait; `longRunning` verbs keep working after a timeout - poll `statusVerb`.++## Verbs by group+++**Lifecycle:** `fusion_start` `fusion_stop` `fusion_kill` `fusion_close_window` `fusion_get_app_state` +**Cloud search & files (APS):** `fusion_aps_status` `fusion_aps_set_client_id` `fusion_aps_signin` `fusion_aps_search` `fusion_aps_open` `fusion_open_by_urn` `fusion_aps_browse` `fusion_aps_recent` `fusion_aps_file_info` `fusion_aps_versions` `fusion_aps_download` `fusion_aps_upload` `fusion_aps_create_folder` `fusion_aps_get` `fusion_walk_cloud_tree` `fusion_search_cloud_files` +**Electronics:** `fusion_show_schematic` `fusion_show_2d_board` `fusion_show_3d_board` `fusion_board_info` `fusion_open_lbr` `fusion_run_modeling_script` +**CAD & 3D export:** `fusion_export_step` `fusion_export_iges` `fusion_export_stl` `fusion_export_3mf` `fusion_export_usdz` `fusion_export_obj` `fusion_export_dxf` `fusion_export_dwg` +**Manufacturing:** `fusion_export_gerbers` `fusion_export_bom` `fusion_export_cpl` `fusion_set_design_rules` `fusion_load_design_rules` `fusion_detect_layers` `fusion_dismiss_blocking_dialogs` `fusion_electron_run` `fusion_electron_zoom` `fusion_electron_pan` `fusion_electron_select` +**Self-describe:** `fusion_describe` ++---++## Lifecycle++### `fusion_start`++Launch Fusion 360 (if needed) and wait for the AdomBridge add-in to be ready.++**Input** `{}`++**Example call:**++```+adom-desktop fusion_start '{}'+```++**Output** (shape):++```json+{+  "success": "bool",+  "addinReady": "bool",+  "status": "str"+}+```++_timeout 150s · long-running (poll `fusion_get_app_state`)_++### `fusion_stop`++Gracefully STOP Fusion 360: close docs cleanly + WM_CLOSE, then wait. NO force-kill - the clean opposite of fusion_start. If a window will not close it returns failure; use fusion_kill then.++**Input** (schema):++```json+{+  "skipCleanClose": "optional bool"+}+```++**Example call:**++```+adom-desktop fusion_stop '{}'+```++**Output** (shape):++```json+{+  "success": "bool",+  "output": "str"+}+```++_timeout 60s_++### `fusion_kill`++Force-KILL Fusion 360 (taskkill /F) - the desperate path for when fusion_stop cannot close it (stuck modal / wedged process). Closes docs cleanly first when reachable.++**Input** (schema):++```json+{+  "skipCleanClose": "optional bool"+}+```++**Example call:**++```+adom-desktop fusion_kill '{}'+```++**Output** (shape):++```json+{+  "success": "bool",+  "output": "str"+}+```++_timeout 30s_++### `fusion_close_window`++Close the active Fusion document/window.++**Input** (schema):++```json+{+  "name": "optional str (default: active)"+}+```++**Example call:**++```+adom-desktop fusion_close_window '{}'+```++**Output** (shape):++```json+{+  "success": "bool"+}+```++_timeout 30s_++### `fusion_get_app_state`++Current app state: running, active document, workspace, isElectronics. The poll/status verb for long-running calls.++**Input** `{}`++**Example call:**++```+adom-desktop fusion_get_app_state '{}'+```++**Output** (shape):++```json+{+  "activeDocument": "str",+  "activeWorkspace": "str",+  "isElectronics": "bool"+}+```++_timeout 20s_++## Cloud search & files (APS)++### `fusion_aps_status`++APS state: configured, signed in, token live, never-charge meter.++**Input** `{}`++**Example call:**++```+adom-desktop fusion_aps_status '{}'+```++**Output** (shape):++```json+{+  "configured": "bool",+  "signedIn": "bool",+  "neverCharge": "bool"+}+```++_timeout 20s_++### `fusion_aps_set_client_id`++Set the org's APS (PKCE) client id used for cloud search.++**Input** (schema):++```json+{+  "clientId": "required str"+}+```++**Example call:**++```+adom-desktop fusion_aps_set_client_id '{"clientId": "D5nn...EPAq"}'+```++**Output** (shape):++```json+{+  "success": "bool"+}+```++_timeout 20s_++### `fusion_aps_signin`++Open the Autodesk sign-in in the browser; a background listener captures the token.++**Input** `{}`++**Example call:**++```+adom-desktop fusion_aps_signin '{}'+```++**Output** (shape):++```json+{+  "success": "bool",+  "authUrl": "str"+}+```++_timeout 30s_++### `fusion_aps_search`++Server-indexed search across the whole team hub (seconds, not a 30-min folder walk).++**Input** (schema):++```json+{+  "query": "required str",+  "limit": "optional int (default 50)",+  "hubId": "optional str",+  "projectId": "optional str"+}+```++**Example call:**++```+adom-desktop fusion_aps_search '{"query": "Molecule", "limit": 10}'+```++**Output** (shape):++```json+{+  "count": "int",+  "results": "[{name,id,projectName,lastModified}]"+}+```++_timeout 60s_++### `fusion_aps_open`++Find a cloud design by name and open it in Fusion (any folder depth). Fire-and-poll.++**Input** (schema):++```json+{+  "query": "required str",+  "wait": "optional bool"+}+```++**Example call:**++```+adom-desktop fusion_aps_open '{"query": "BME690 Molecule"}'+```++**Output** (shape):++```json+{+  "opening": "bool",+  "match": "{name}",+  "statusVerb": "str"+}+```++_timeout 60s · long-running (poll `fusion_get_app_state`)_++### `fusion_open_by_urn`++Open a cloud ELECTRONICS DESIGN by URN. PCB/ELECTRONICS NAV RULE: a board is NOT a standalone file - the schematic, 2D board and 3D board are VIEWS inside ONE electronics DESIGN. Open the DESIGN document first (fusion_open_cloud_file or fusion_open_by_urn), THEN switch to its schematic and its 2D board (fusion_show_2d_board) and 3D board (fusion_show_3d_board). A Select-Electronics-Design-File picker IS that design list of its schematic + board. An EMPTY 2D board usually means you opened a derivative or the wrong file, or it is out of sync - reopen the parent electronics DESIGN and switch to its board view; do NOT open a .brd or .sch as a standalone file.++**Input** (schema):++```json+{+  "urn": "required str"+}+```++**Example call:**++```+adom-desktop fusion_open_by_urn '{"urn": "urn:adsk.wipprod:fs.file:vf.xxxx?version=1"}'+```++**Output** (shape):++```json+{+  "success": "bool",+  "output": "str"+}+```++_timeout 240s · long-running (poll `fusion_get_app_state`)_++### `fusion_aps_browse`++Browse hubs/projects/folders without launching Fusion.++**Input** (schema):++```json+{+  "hubId": "optional str",+  "projectId": "optional str",+  "folderId": "optional str"+}+```++**Example call:**++```+adom-desktop fusion_aps_browse '{}'+```++**Output** (shape):++```json+{+  "items": "[{name,type,id}]"+}+```++_timeout 60s_++### `fusion_aps_recent`++Most-recently-modified designs across the team hub, newest first.++**Input** (schema):++```json+{+  "limit": "optional int (default 25)"+}+```++**Example call:**++```+adom-desktop fusion_aps_recent '{"limit": 25}'+```++**Output** (shape):++```json+{+  "count": "int",+  "results": "[...]"+}+```++_timeout 60s_++### `fusion_aps_file_info`++Version history + who/when/size for a file (tip + recent versions).++**Input** (schema):++```json+{+  "query": "str  OR  projectId+urn"+}+```++**Example call:**++```+adom-desktop fusion_aps_file_info '{"query": "BME690 Molecule"}'+```++**Output** (shape):++```json+{+  "versionCount": "int",+  "tip": "{...}",+  "versions": "[...]"+}+```++_timeout 40s_++### `fusion_aps_versions`++Full (uncapped) version history of a file.++**Input** (schema):++```json+{+  "query": "str  OR  projectId+urn"+}+```++**Example call:**++```+adom-desktop fusion_aps_versions '{"query": "BME690 Molecule"}'+```++**Output** (shape):++```json+{+  "versionCount": "int",+  "versions": "[...]"+}+```++_timeout 40s_++### `fusion_aps_download`++Download a cloud file to the local machine (no Fusion needed).++**Input** (schema):++```json+{+  "query": "str OR projectId+urn",+  "saveDir": "optional str",+  "fileName": "optional str"+}+```++**Example call:**++```+adom-desktop fusion_aps_download '{"query": "BME690 Molecule"}'+```++**Output** (shape):++```json+{+  "path": "str",+  "bytes": "int"+}+```++_timeout 90s_++### `fusion_aps_upload`++Upload a local file as a NEW cloud file (free Data Management; needs data:write scope).++**Input** (schema):++```json+{+  "projectId": "required str",+  "folderId": "required str",+  "localPath": "required str",+  "fileName": "optional str"+}+```++**Example call:**++```+adom-desktop fusion_aps_upload '{"projectId": "a.YnVz...", "folderId": "urn:...", "localPath": "C:/x.f3d"}'+```++**Output** (shape):++```json+{+  "itemUrn": "str",+  "bytes": "int"+}+```++_timeout 90s_++### `fusion_aps_create_folder`++Create a subfolder in a project (free; needs data:create scope).++**Input** (schema):++```json+{+  "projectId": "required str",+  "parentFolderId": "required str",+  "name": "required str"+}+```++**Example call:**++```+adom-desktop fusion_aps_create_folder '{"projectId": "a.YnVz...", "parentFolderId": "urn:...", "name": "new-folder"}'+```++**Output** (shape):++```json+{+  "folderId": "str"+}+```++_timeout 50s_++### `fusion_aps_get`++Raw authenticated GET against a free APS path (dev/verify helper).++**Input** (schema):++```json+{+  "path": "required str"+}+```++**Example call:**++```+adom-desktop fusion_aps_get '{"path": "/project/v1/hubs"}'+```++**Output** (shape):++```json+{+  "status": "int",+  "body": "obj"+}+```++_timeout 40s_++### `fusion_walk_cloud_tree`++DO NOT USE: slow in-app add-in walk (30+ min) that CAN CRASH Fusion (WinError 10054). Use fusion_aps_search instead; see the 'fusion-aps-search' skill.++**Input** `{}`++**Example call:**++```+adom-desktop fusion_walk_cloud_tree '{}'+```++**Output** (shape):++```json+{+  "tree": "obj"+}+```++_timeout 600s · long-running (poll `fusion_get_app_state`)_++### `fusion_search_cloud_files`++DO NOT USE: slow in-app add-in search (30+ min) that CAN CRASH Fusion (WinError 10054). Use fusion_aps_search instead; see the 'fusion-aps-search' skill.++**Input** (schema):++```json+{+  "query": "required str"+}+```++**Example call:**++```+adom-desktop fusion_search_cloud_files '{"query": "Molecule"}'+```++**Output** (shape):++```json+{+  "results": "[...]"+}+```++_timeout 180s · long-running (poll `fusion_get_app_state`)_++## Electronics++### `fusion_show_schematic`++Switch the OPEN electronics design to its SCHEMATIC view (the symmetric partner of fusion_show_2d_board / fusion_show_3d_board, via Fusion's SwitchSchDocCmd). A VIEW of the project, not a standalone file. Drive it for demos with fusion_electron_zoom / _pan / _select.++**Input** `{}`++**Example call:**++```+adom-desktop fusion_show_schematic '{}'+```++**Output** (shape):++```json+{+  "success": "bool",+  "activeWorkspace": "str",+  "productType": "str"+}+```++_timeout 70s · long-running (poll `fusion_get_app_state`)_++### `fusion_show_2d_board`++Switch the OPEN electronics design to its 2D PCB Editor (board layout) view. This is a VIEW of the project, not a file to open standalone - if the board is empty, you opened a child/derivative instead of the EcadDesignProductType PROJECT; reopen the project. Drive the view with fusion_electron_run WINDOW commands.++**Input** `{}`++**Example call:**++```+adom-desktop fusion_show_2d_board '{}'+```++**Output** (shape):++```json+{+  "activeWorkspace": "str"+}+```++_timeout 70s · long-running (poll `fusion_get_app_state`)_++### `fusion_show_3d_board`++Switch the OPEN electronics design to its 3D PCB view (populated board). A VIEW of the project, not a standalone file. Orbit it for demos via fusion_run_modeling_script (app.activeViewport.camera + vp.refresh()).++**Input** `{}`++**Example call:**++```+adom-desktop fusion_show_3d_board '{}'+```++**Output** (shape):++```json+{+  "activeWorkspace": "str",+  "screenshots": "[...]"+}+```++_timeout 70s · long-running (poll `fusion_get_app_state`)_++### `fusion_board_info`++Raw board geometry XML (copper/arcs/lines) for the open board.++**Input** `{}`++**Example call:**++```+adom-desktop fusion_board_info '{}'+```++**Output** (shape):++```json+{+  "rawXml": "str"+}+```++_timeout 60s_++### `fusion_open_lbr`++Import an EAGLE .lbr library into Fusion's Electronics library editor.++**Input** (schema):++```json+{+  "filePath": "required str (.lbr on the machine)",+  "symbolName": "optional str",+  "verify": "optional bool"+}+```++**Example call:**++```+adom-desktop fusion_open_lbr '{"filePath": "C:/libs/nRF52840-CKAA.lbr"}'+```++**Output** (shape):++```json+{+  "success": "bool",+  "postOpenScreenshot": "{savedTo}"+}+```++_timeout 50s_++### `fusion_run_modeling_script`++Run an adsk.fusion modeling script in the live session (sketches/extrudes/params). Free programmatic CAD.++**Input** (schema):++```json+{+  "script": "required str (Python using adsk; globals: adsk, app, ui, design)"+}+```++**Example call:**++```+adom-desktop fusion_run_modeling_script '{"script": "import adsk.fusion\n# ...build geometry..."}'+```++**Output** (shape):++```json+{+  "result": "obj",+  "documentName": "str"+}+```++_timeout 180s · long-running (poll `fusion_get_app_state`)_++## CAD & 3D export++### `fusion_export_step`++Export the active design to STEP (needs the 3D view).++**Input** (schema):++```json+{+  "outputPath": "required str"+}+```++**Example call:**++```+adom-desktop fusion_export_step '{"outputPath": "C:/out/board.step"}'+```++**Output** (shape):++```json+{+  "format": "str",+  "fileSizeKB": "int"+}+```++_timeout 300s · long-running (poll `fusion_get_app_state`)_++### `fusion_export_iges`++Export to IGES.++**Input** (schema):++```json+{+  "outputPath": "required str"+}+```++**Example call:**++```+adom-desktop fusion_export_iges '{"outputPath": "C:/out/board.iges"}'+```++**Output** (shape):++```json+{+  "format": "str"+}+```++_timeout 300s · long-running (poll `fusion_get_app_state`)_++### `fusion_export_stl`++Export to STL mesh.++**Input** (schema):++```json+{+  "outputPath": "required str"+}+```++**Example call:**++```+adom-desktop fusion_export_stl '{"outputPath": "C:/out/part.stl"}'+```++**Output** (shape):++```json+{+  "format": "str"+}+```++_timeout 300s · long-running (poll `fusion_get_app_state`)_++### `fusion_export_3mf`++Export to 3MF mesh.++**Input** (schema):++```json+{+  "outputPath": "required str"+}+```++**Example call:**++```+adom-desktop fusion_export_3mf '{"outputPath": "C:/out/part.3mf"}'+```++**Output** (shape):++```json+{+  "format": "str"+}+```++_timeout 300s · long-running (poll `fusion_get_app_state`)_++### `fusion_export_usdz`++Export to USDZ (AR / Hydrogen 3D).++**Input** (schema):++```json+{+  "outputPath": "required str"+}+```++**Example call:**++```+adom-desktop fusion_export_usdz '{"outputPath": "C:/out/part.usdz"}'+```++**Output** (shape):++```json+{+  "format": "str"+}+```++_timeout 300s · long-running (poll `fusion_get_app_state`)_++### `fusion_export_obj`++Export to OBJ mesh.++**Input** (schema):++```json+{+  "outputPath": "required str"+}+```++**Example call:**++```+adom-desktop fusion_export_obj '{"outputPath": "C:/out/part.obj"}'+```++**Output** (shape):++```json+{+  "format": "str"+}+```++_timeout 300s · long-running (poll `fusion_get_app_state`)_++### `fusion_export_dxf`++Export 2D DXF.++**Input** (schema):++```json+{+  "outputPath": "required str"+}+```++**Example call:**++```+adom-desktop fusion_export_dxf '{"outputPath": "C:/out/sketch.dxf"}'+```++**Output** (shape):++```json+{+  "format": "str"+}+```++_timeout 120s · long-running (poll `fusion_get_app_state`)_++### `fusion_export_dwg`++Export 2D DWG.++**Input** (schema):++```json+{+  "outputPath": "required str"+}+```++**Example call:**++```+adom-desktop fusion_export_dwg '{"outputPath": "C:/out/sketch.dwg"}'+```++**Output** (shape):++```json+{+  "format": "str"+}+```++_timeout 120s · long-running (poll `fusion_get_app_state`)_++## Manufacturing++### `fusion_export_gerbers`++Run the bundled JLCPCB CAM job (auto 2/4-layer) to produce the gerber + drill ZIP.++**Input** (schema):++```json+{+  "outputDir": "optional str (default C:/tmp/adom-gerbers)"+}+```++**Example call:**++```+adom-desktop fusion_export_gerbers '{"outputDir": "C:/tmp/jlc"}'+```++**Output** (shape):++```json+{+  "fileCount": "int",+  "files": "[{name,size}]",+  "zipPath": "str"+}+```++_timeout 180s · long-running (poll `fusion_get_app_state`)_++### `fusion_export_bom`++Export a Bill of Materials CSV (grouped by value+package) from the open board.++**Input** (schema):++```json+{+  "outputPath": "optional str",+  "grouped": "optional bool (default true)"+}+```++**Example call:**++```+adom-desktop fusion_export_bom '{"outputPath": "C:/tmp/bom.csv"}'+```++**Output** (shape):++```json+{+  "componentCount": "int",+  "grouped": "bool"+}+```++_timeout 60s_++### `fusion_export_cpl`++Export the Component Placement List (pick-and-place) CSV.++**Input** (schema):++```json+{+  "outputPath": "optional str",+  "side": "optional str (all|top|bottom)"+}+```++**Example call:**++```+adom-desktop fusion_export_cpl '{"outputPath": "C:/tmp/cpl.csv"}'+```++**Output** (shape):++```json+{+  "topCount": "int",+  "bottomCount": "int"+}+```++_timeout 60s_++### `fusion_set_design_rules`++Load manufacturing-grade DRC into the open board (JLCPCB 2/4-layer profiles).++**Input** (schema):++```json+{+  "action": "optional str (apply|export|show)",+  "layers": "optional str (auto|2|4)"+}+```++**Example call:**++```+adom-desktop fusion_set_design_rules '{"action": "apply", "layers": "2"}'+```++**Output** (shape):++```json+{+  "activeWorkspace": "str",+  "description": "str"+}+```++_timeout 90s_++### `fusion_load_design_rules`++Load a bundled .edru design-rule set into the board.++**Input** (schema):++```json+{+  "layers": "optional str (auto|2|4)"+}+```++**Example call:**++```+adom-desktop fusion_load_design_rules '{}'+```++**Output** (shape):++```json+{+  "success": "bool"+}+```++_timeout 90s_++### `fusion_detect_layers`++Detect 2-layer vs 4-layer board (ULP + CAM comparison).++**Input** `{}`++**Example call:**++```+adom-desktop fusion_detect_layers '{}'+```++**Output** (shape):++```json+{+  "layerCount": "int",+  "copperLayers": "[int]"+}+```++_timeout 90s_++### `fusion_dismiss_blocking_dialogs`++Detect + classify (and optionally dismiss) blocking Fusion dialogs.++**Input** `{}`++**Example call:**++```+adom-desktop fusion_dismiss_blocking_dialogs '{}'+```++**Output** (shape):++```json+{+  "dialogs": "[...]"+}+```++_timeout 30s_++### `fusion_electron_run`++Run an EAGLE/Electron command in the open board (the generic extension point, e.g. RUN <ulp>).++**Input** (schema):++```json+{+  "command": "required str"+}+```++**Example call:**++```+adom-desktop fusion_electron_run '{"command": "set confirm yes;RUN 'C:/tmp/jlcpcb_smta_exporter.ulp' 'C:/tmp/jlc'"}'+```++**Output** (shape):++```json+{+  "success": "bool",+  "output": "str"+}+```++_timeout 90s_++### `fusion_electron_zoom`++Smoothly ZOOM the schematic/2D board for a recording (the whole motion is one call). factor>1 zooms in, <1 out; or fit:true. The loop runs in the add-in with a repaint per frame.++**Input** (schema):++```json+{+  "factor": "float (default 2.0)",+  "fit": "optional bool",+  "steps": "optional int (default 16)",+  "frameDelayMs": "optional int (default 35)"+}+```++**Example call:**++```+adom-desktop fusion_electron_zoom '{"factor": 3, "steps": 20}'+```++**Output** (shape):++```json+{+  "success": "bool",+  "output": "str"+}+```++_timeout 60s · long-running (poll `fusion_get_app_state`)_++### `fusion_electron_pan`++Smoothly PAN + zoom the view to frame a board-coordinate box (mm; get part positions from fusion_board_info). Animates from where the view last was.++**Input** (schema):++```json+{+  "x1": "float",+  "y1": "float",+  "x2": "float",+  "y2": "float",+  "steps": "optional int (default 16)",+  "frameDelayMs": "optional int (default 35)"+}+```++**Example call:**++```+adom-desktop fusion_electron_pan '{"x1": 0, "y1": 0, "x2": 10, "y2": 8}'+```++**Output** (shape):++```json+{+  "success": "bool",+  "output": "str",+  "box": "[...]"+}+```++_timeout 60s · long-running (poll `fusion_get_app_state`)_++### `fusion_electron_select`++SELECT a part (by reference designator, or x/y board mm) and surface its properties - the way clicking a part reveals the properties panel. Great for showing life in a recording.++**Input** (schema):++```json+{+  "name": "str (refdes, e.g. R1)",+  "x": "optional float",+  "y": "optional float",+  "properties": "optional bool (default true)"+}+```++**Example call:**++```+adom-desktop fusion_electron_select '{"name": "U1"}'+```++**Output** (shape):++```json+{+  "success": "bool",+  "output": "str",+  "deviceInfo": "str"+}+```++_timeout 30s · long-running (poll `fusion_get_app_state`)_++## Self-describe++### `fusion_describe`++Self-describe every verb the bridge exposes (this list) for AD's Verbs tab + runner.++**Input** `{}`++**Example call:**++```+adom-desktop fusion_describe '{}'+```++**Output** (shape):++```json+{+  "success": "bool",+  "verbs": "[{name,summary,input,output,timeoutSeconds,statusVerb,longRunning,example}]"+}+```++_timeout 20s_
ad_client.pyadded+280
@@ -0,0 +1,280 @@+"""Outbound calls from this bridge BACK to Adom Desktop (AD) core.++Why this exists: as of **AD 1.9.84** a bridge's loopback callback+(`POST $ADOM_DIRECT_API_URL/command`) reaches the FULL AD verb set - not just+`desktop_*`. That means this bridge can, on its own:++  * `notify_user` the user directly (it used to be "Unknown desktop command", so+    the old code returned a `notifyUser` PAYLOAD and asked the driving AI to relay+    it - a workaround, now dropped);+  * enumerate peer ADs on the relay (`targets`) and route ANY verb to one via a+    cross-AD `target` - so a bridge running on a VM can reach the user on their+    LAPTOP ("notify them where they actually are").++Everything here is BEST-EFFORT and never raises: an older AD (pre-1.9.84), a+missing env var, or a closed port just yields None/False and the caller falls+back to its prior behavior. We CAPABILITY-PROBE (`GET /commands`) rather than+hardcode, per the SDK, so this keeps working as the verb set evolves.++Auth model (from disc #78): `X-Adom-Bridge-Token` = ATTRIBUTION only (AD binds+127.0.0.1 and trusts-by-install), so calls run ungated; a stale token 403s, so we+re-read it from the env on every call.+"""++import json+import os+import urllib.request+import urllib.error++_TIMEOUT = 8+# Cache the capability set for the process lifetime (the AD verb surface doesn't+# change under a running AD). None = not-yet-probed / unreachable.+_caps_cache = None+_self_name_cache = None+++_discovered_base = None  # None = not tried, "" = tried+failed, str = discovered base URL+++def _raw_get(url, timeout=4):+    """Low-level GET that does NOT go through _base_url (used by discovery so it can't recurse).+    Returns parsed JSON, or None."""+    try:+        req = urllib.request.Request(url, headers={"Accept": "application/json"}, method="GET")+        with urllib.request.urlopen(req, timeout=timeout) as resp:+            return json.loads(resp.read().decode("utf-8", "replace"))+    except Exception:+        return None+++def _looks_like_ad_api(data) -> bool:+    """Does a /commands response look like AD's verb catalog (so we don't bind a random service)?"""+    if isinstance(data, dict):+        if isinstance(data.get("commands"), list):+            return True+        # AD's /commands also carries a _hint mentioning POST /command+        if "command" in (data.get("_hint") or "").lower():+            return True+    return isinstance(data, list)+++def _discover_direct_api():+    """Find AD's loopback direct-API base by port-probing, for the case where AD did NOT inject+    ADOM_DIRECT_API_URL into our spawn env (seen live on an AD 1.9.103 Hyper-V VM: the direct API+    WAS up on 127.0.0.1 but the env var was absent, so available() short-circuited to False and the+    bridge fell back to slow CLI relays - John caught it 2026-07-14). We enumerate the loopback TCP+    ports adom-desktop.exe is LISTENING on and probe each `/commands`; the one that returns AD's verb+    catalog is the direct API. Cached for the process lifetime. Windows-only + best-effort; never raises."""+    global _discovered_base+    if _discovered_base:                # cache SUCCESS only; a transient miss must not stick forever+        return _discovered_base+    try:+        import subprocess as _sp, re as _re+        cnw = getattr(_sp, "CREATE_NO_WINDOW", 0)+        tl = _sp.run(["tasklist", "/FI", "IMAGENAME eq adom-desktop.exe", "/FO", "CSV", "/NH"],+                     capture_output=True, text=True, timeout=8, creationflags=cnw).stdout+        pids = set(_re.findall(r'"adom-desktop\.exe","(\d+)"', tl))+        if not pids:+            return None+        ns = _sp.run(["netstat", "-ano", "-p", "TCP"], capture_output=True, text=True,+                     timeout=8, creationflags=cnw).stdout+        seen = []+        for line in ns.splitlines():+            m = _re.search(r'\s(?:127\.0\.0\.1|\[::1\]):(\d+)\s+\S+\s+LISTENING\s+(\d+)', line)+            if m and m.group(2) in pids:+                p = int(m.group(1))+                if p not in seen:+                    seen.append(p)+        for p in seen:+            base = f"http://127.0.0.1:{p}"+            if _looks_like_ad_api(_raw_get(base + "/commands")):+                _discovered_base = base+                return base+    except Exception:+        pass+    return None+++def _base_url():+    """The loopback direct-API base: the URL AD injects into our spawn env, else one we DISCOVER by+    probing adom-desktop's loopback ports (AD sometimes fails to inject the env var even though the+    API is up - see _discover_direct_api). None only if neither yields a reachable API."""+    env = (os.environ.get("ADOM_DIRECT_API_URL") or "").rstrip("/")+    if env:+        return env+    return _discover_direct_api()+++def _token():+    # Re-read every call: after an AD restart the old token 403s.+    return os.environ.get("ADOM_BRIDGE_TOKEN") or ""+++def _http(method, path, body=None, timeout=_TIMEOUT):+    """Best-effort JSON request to the direct API. Returns parsed dict/list or None."""+    base = _base_url()+    if not base:+        return None+    url = base + path+    data = None+    headers = {"Accept": "application/json"}+    tok = _token()+    if tok:+        headers["X-Adom-Bridge-Token"] = tok+    if body is not None:+        data = json.dumps(body).encode("utf-8")+        headers["Content-Type"] = "application/json"+    req = urllib.request.Request(url, data=data, headers=headers, method=method)+    try:+        with urllib.request.urlopen(req, timeout=timeout) as resp:+            raw = resp.read().decode("utf-8", "replace")+    except Exception:+        return None+    try:+        return json.loads(raw)+    except Exception:+        return None+++def available() -> bool:+    """True if the direct API is reachable at all (env var present + port open)."""+    if not _base_url():+        return False+    return capabilities() is not None+++def _names_from_list(items):+    """Collect verb names from a list of strings and/or {name|command|verb} dicts."""+    out = set()+    for it in items or []:+        if isinstance(it, str):+            out.add(it)+        elif isinstance(it, dict):+            n = it.get("name") or it.get("command") or it.get("verb")+            if n:+                out.add(n)+    return out+++def _parse_command_names(data):+    """Extract the full verb-name set from a /commands response, tolerant of BOTH the legacy+    `{"commands":[...]}` shape AND the current AD (1.9.x) shape, where verbs are split across:+      topLevel: ["notify_user", "targets", ...]            (flat name list)+      cliRequired: ["pull_file", "shell_execute", ...]     (flat name list)+      bridges: [{name, verbs:[...]}, ...]                  (per-bridge verb lists)+      desktop: {commands:["screenshot_window", ...]}       (SHORT names; real verb = "desktop_"+name)+    Without this, capabilities() returned None on every current AD, so available() was always False+    and the bridge silently fell back to slow CLI relays (root-caused live, John 2026-07-14)."""+    names = set()+    if isinstance(data, list):+        return _names_from_list(data)+    if not isinstance(data, dict):+        return names+    if isinstance(data.get("commands"), list):          # legacy shape+        names |= _names_from_list(data["commands"])+    for k in ("topLevel", "cliRequired"):               # current: flat name lists+        if isinstance(data.get(k), list):+            names |= _names_from_list(data[k])+    for b in (data.get("bridges") or []):               # current: per-bridge verb lists+        if isinstance(b, dict):+            names |= _names_from_list(b.get("verbs"))+    dk = data.get("desktop")                            # current: desktop short names -> desktop_*+    if isinstance(dk, dict):+        for c in (dk.get("commands") or []):+            if isinstance(c, str):+                names.add(c)+                names.add("desktop_" + c)+    return names+++def capabilities():+    """Set of AD command names from `GET /commands` (cached). None if unreachable/unparseable."""+    global _caps_cache+    if _caps_cache is not None:+        return _caps_cache+    data = _http("GET", "/commands")+    if data is None:+        return None+    names = _parse_command_names(data)+    if not names:+        return None+    _caps_cache = names+    return names+++def has(command: str):+    """True/False if `command` is in the probed capability set; None if unknown+    (probe failed). Callers should try when the answer isn't an explicit False."""+    caps = capabilities()+    if caps is None:+        return None+    return command in caps+++def call(command: str, args=None, target=None, timeout=_TIMEOUT):+    """Dispatch ANY AD verb back through the direct API. Returns the parsed JSON+    response dict, or None on any failure (never raises).++    target: a peer AD clientName (from `peers()`), or "all" to fan out. Omit to+    run on THIS AD (the one hosting the bridge)."""+    payload = {"command": command}+    if args:+        payload["args"] = args+    if target:+        payload["target"] = target+    return _http("POST", "/command", body=payload, timeout=timeout)+++def self_name():+    """This AD's own clientName (to exclude it from peer routing). Best-effort."""+    global _self_name_cache+    if _self_name_cache is not None:+        return _self_name_cache or None+    st = _http("GET", "/status") or {}+    name = st.get("clientName") or st.get("name") or st.get("hostname")+    _self_name_cache = name or ""+    return name or None+++def peers():+    """clientNames of the OTHER ADs on the relay (excludes self). [] if none/unknown."""+    res = call("targets") or {}+    # tolerate shape drift: the peer list is under `clients` on current AD, `targets` on older.+    tlist = None+    if isinstance(res, dict):+        tlist = res.get("targets") or res.get("clients")+    if not isinstance(tlist, list):+        return []+    me = self_name()+    out = []+    for t in tlist:+        n = t if isinstance(t, str) else ((t or {}).get("name") or (t or {}).get("hostname") or (t or {}).get("clientName"))+        if n and n != me:+            out.append(n)+    return out+++def notify(title, body, level="info", buttons=None, target=None, reach_user=False):+    """Fire an AD `notify_user` toast. Returns the response dict, or None if the+    direct API is unreachable or AD is too old to have notify_user (caller falls+    back to returning a notifyUser payload for the driving AI to relay).++    reach_user: when this bridge may be running UNATTENDED (e.g. on a VM) while the+    user is on another machine, set True to also reach peer ADs. Since AD can't yet+    resolve which peer is "attended", we fan out to "all" when peers exist so the+    toast lands wherever the user actually is. `target` (explicit) overrides this.+    """+    if has("notify_user") is False:+        return None+    args = {"title": title, "body": body, "level": level}+    if buttons:+        args["buttons"] = buttons+    tgt = target+    if tgt is None and reach_user:+        # Fan out to EVERY connected desktop so the toast lands wherever the user actually is. Do NOT+        # gate on peers() (John 2026-07-14): the `targets` response shape drifted to {clients:[...]}+        # so peers() wrongly returns [] and the toast would hit only THIS (unattended VM). The relay+        # honors target="all" directly - verified reaching the user's laptop.+        tgt = "all"+    res = call("notify_user", args, target=tgt)+    return res
addin/AdomBridge/._AdomBridge.manifestadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/._AdomBridge.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/._http_server.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/AdomBridge.manifestadded+12
@@ -0,0 +1,12 @@+{+    "autodeskProduct": "Fusion",+    "type": "addin",+    "id": "com.adom.bridge",+    "author": "Adom Industries, Inc.",+    "description": {+        "": "Adom Desktop Conduit bridge add-in. Exposes a localhost HTTP API for external automation of Fusion 360."+    },+    "version": "1.0.4",+    "runOnStartup": true,+    "supportedOS": "windows|mac"+}\ No newline at end of file
addin/AdomBridge/AdomBridge.pyadded+109
@@ -0,0 +1,109 @@+"""Adom Bridge — Fusion 360 Add-In.++Starts a localhost HTTP server on a background thread (port 8774).+Incoming commands are marshaled to the main Fusion thread via a CustomEvent,+so all Fusion API calls execute safely on the main thread.+"""++import adsk.core+import adsk.fusion+import traceback++# Module-level references kept alive for the add-in lifetime+_app = None+_ui = None+_custom_event = None+_event_handler = None+_http_thread = None++CUSTOM_EVENT_ID = "AdomBridgeCommandEvent"+++class CommandEventHandler(adsk.core.CustomEventHandler):+    """Handles custom events fired from the HTTP background thread.++    Each event's additionalInfo is a JSON string with {request_id, command, args}.+    The handler dispatches to the appropriate command function, then stores+    the result so the HTTP thread can return it.+    """++    def __init__(self):+        super().__init__()++    def notify(self, args: adsk.core.CustomEventArgs):+        try:+            import json+            from . import http_server+            from .commands import dispatch_command++            info = json.loads(args.additionalInfo)+            request_id = info["request_id"]+            command = info["command"]+            cmd_args = info.get("args", {})++            # Staleness check: if the HTTP waiter already timed out and+            # bailed, skip the work entirely. Saves main-thread time on+            # heavy exports whose caller already gave up.+            if not http_server.is_request_alive(request_id):+                adsk.core.Application.log(+                    f"AdomBridge: skipping stale request {request_id[:8]} ({command}) — HTTP waiter gone"+                )+                return++            try:+                result = dispatch_command(_app, command, cmd_args)+            except Exception as e:+                result = {"success": False, "error": f"Command error: {e}\n{traceback.format_exc()}"}++            http_server.set_result(request_id, result)++        except Exception:+            traceback.print_exc()+++def run(context):+    """Called by Fusion 360 when the add-in starts."""+    global _app, _ui, _custom_event, _event_handler, _http_thread++    try:+        _app = adsk.core.Application.get()+        _ui = _app.userInterface++        # Register the custom event for thread marshaling+        _custom_event = _app.registerCustomEvent(CUSTOM_EVENT_ID)+        _event_handler = CommandEventHandler()+        _custom_event.add(_event_handler)++        # Start the HTTP server on a background daemon thread+        from . import http_server+        _http_thread = http_server.start(CUSTOM_EVENT_ID, _app)++        # Log to the Text Commands palette (non-blocking)+        adsk.core.Application.log(f"Adom Bridge add-in started (port 8774)")++    except Exception:+        # Only use messageBox for errors — worth blocking to show the user+        if _ui:+            _ui.messageBox(f"Adom Bridge failed to start:\n{traceback.format_exc()}")+++def stop(context):+    """Called by Fusion 360 when the add-in stops."""+    global _app, _ui, _custom_event, _event_handler, _http_thread++    try:+        # Stop HTTP server+        from . import http_server+        http_server.stop()++        # Unregister custom event+        if _app and _custom_event:+            _app.unregisterCustomEvent(CUSTOM_EVENT_ID)++        _custom_event = None+        _event_handler = None+        _http_thread = None++    except Exception:+        if _ui:+            _ui.messageBox(f"Adom Bridge stop error:\n{traceback.format_exc()}")
addin/AdomBridge/commands/.___init__.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._app_state.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._assembly_bom.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._close_document.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._cloud_documents.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._design_info.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._document_info.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._electron_view.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._electronics.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._export.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._import_file.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._manufacturing.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._modeling.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._open_electronics_file.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._open_lbr.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._parameters.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._physical_properties.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._screenshot.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/._silkscreen_capture.pyadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/commands/__init__.pyadded+143
@@ -0,0 +1,143 @@+"""Command dispatch for the Adom Bridge Fusion 360 add-in."""++import adsk.core++from .app_state import handle_get_app_state+from .document_info import handle_document_info, handle_activate_document+from .export import (+    handle_export_step, handle_export_stl, handle_export_3mf,+    handle_export_f3d, handle_export_usdz, handle_export_fbx,+    handle_export_dxf, handle_export_dwg, handle_export_iges,+    handle_export_obj, handle_export_sat, handle_export_skp,+)+from .design_info import handle_get_design_info+from .electronics import (+    handle_electron_run,+    handle_execute_text_command,+    handle_export_source,+    handle_export_eagle_source,+    handle_open_electronics,+    handle_list_text_commands,+    handle_board_info,+)+from .electron_view import handle_electron_zoom, handle_electron_pan, handle_electron_select+from .open_lbr import handle_open_lbr, handle_export_lbr+from .import_file import handle_import_file+from .parameters import handle_get_parameters, handle_set_parameter+from .screenshot import handle_take_screenshot+from .close_document import handle_close_document, handle_close_all_documents+from .open_electronics_file import handle_open_schematic, handle_open_board, handle_show_3d_board, handle_show_2d_board, handle_show_schematic, handle_import_electronics+from .cloud_documents import (+    handle_save_to_cloud,+    handle_list_cloud_projects,+    handle_list_cloud_files,+    handle_delete_cloud_file,+    handle_create_cloud_folder,+    handle_open_cloud_file,+    handle_open_by_urn,+    handle_search_cloud_files,+    handle_export_cloud_file,+    handle_check_recovery,+    handle_walk_cloud_tree,+)+from .manufacturing import (+    handle_export_bom,+    handle_export_cpl,+    handle_export_gerbers,+    handle_set_design_rules,+    handle_export_board_image,+    handle_detect_layers,+)+from .silkscreen_capture import handle_take_silkscreen_screenshot+from .modeling import handle_run_modeling_script+from .assembly_bom import handle_assembly_bom+from .physical_properties import handle_physical_properties++COMMAND_HANDLERS = {+    # App state+    "get_app_state": handle_get_app_state,+    "document_info": handle_document_info,+    "activate_document": handle_activate_document,+    # 3D CAD commands+    "import_file": handle_import_file,+    "export_step": handle_export_step,+    "export_stl": handle_export_stl,+    "export_3mf": handle_export_3mf,+    "export_f3d": handle_export_f3d,+    "export_usdz": handle_export_usdz,+    "export_fbx": handle_export_fbx,+    "export_dxf": handle_export_dxf,+    "export_dwg": handle_export_dwg,+    "export_iges": handle_export_iges,+    "export_obj": handle_export_obj,+    "export_sat": handle_export_sat,+    "export_skp": handle_export_skp,+    "get_design_info": handle_get_design_info,+    "assembly_bom": handle_assembly_bom,+    "physical_properties": handle_physical_properties,+    "get_parameters": handle_get_parameters,+    "set_parameter": handle_set_parameter,+    "take_screenshot": handle_take_screenshot,+    # Electronics commands (EAGLE via Electron.run)+    "electron_run": handle_electron_run,+    "electron_zoom": handle_electron_zoom,+    "electron_pan": handle_electron_pan,+    "electron_select": handle_electron_select,+    "execute_text_command": handle_execute_text_command,+    "open_electronics": handle_open_electronics,+    "list_text_commands": handle_list_text_commands,+    "board_info": handle_board_info,+    "export_source": handle_export_source,+    "export_eagle_source": handle_export_eagle_source,+    # Library file commands (Document.Open / EXPORT SCRIPT)+    "open_lbr": handle_open_lbr,+    "export_lbr": handle_export_lbr,+    # Document management+    "close_document": handle_close_document,+    "close_all_documents": handle_close_all_documents,+    # Electronics file opening+    "open_schematic": handle_open_schematic,+    "open_board": handle_open_board,+    "show_3d_board": handle_show_3d_board,+    "show_2d_board": handle_show_2d_board,+    "show_schematic": handle_show_schematic,+    "import_electronics": handle_import_electronics,+    # Cloud document management+    "save_to_cloud": handle_save_to_cloud,+    "list_cloud_projects": handle_list_cloud_projects,+    "list_cloud_files": handle_list_cloud_files,+    "delete_cloud_file": handle_delete_cloud_file,+    "create_cloud_folder": handle_create_cloud_folder,+    "open_cloud_file": handle_open_cloud_file,+    "open_by_urn": handle_open_by_urn,+    "check_recovery": handle_check_recovery,+    "search_cloud_files": handle_search_cloud_files,+    "walk_cloud_tree": handle_walk_cloud_tree,+    "export_cloud_file": handle_export_cloud_file,+    # Manufacturing exports (Gerbers, BOM, CPL, DRC, images)+    "export_bom": handle_export_bom,+    "export_cpl": handle_export_cpl,+    "export_gerbers": handle_export_gerbers,+    "set_design_rules": handle_set_design_rules,+    "export_board_image": handle_export_board_image,+    "detect_layers": handle_detect_layers,+    # Silkscreen layer capture (isolated top/bottom PNG)+    "take_silkscreen_screenshot": handle_take_silkscreen_screenshot,+    # In-app parametric modeling (free; runs adsk.fusion in the live session)+    "run_modeling_script": handle_run_modeling_script,+}+++def dispatch_command(app: adsk.core.Application, command: str, args: dict) -> dict:+    """Dispatch a command to the appropriate handler.++    All handlers receive the Fusion Application object and an args dict.+    """+    handler = COMMAND_HANDLERS.get(command)+    if handler is None:+        return {+            "success": False,+            "error": f"Unknown add-in command: {command}",+            "_hint": f"Valid add-in commands: {', '.join(sorted(COMMAND_HANDLERS.keys()))}.",+        }+    return handler(app, args)
addin/AdomBridge/commands/app_state.pyadded+127
@@ -0,0 +1,127 @@+"""App state command — list open documents, active workspace, and Fusion state."""++import adsk.core+++def handle_get_app_state(app: adsk.core.Application, args: dict) -> dict:+    """Get the current state of Fusion 360: open documents, active workspace, etc.++    Returns information about every open document/tab, which one is active,+    the current workspace, and product type.+    """+    # Active workspace+    active_workspace = "unknown"+    try:+        ws = app.executeTextCommand("DebugCommands.ActiveWorkspace")+        if ws:+            active_workspace = ws.strip()+    except Exception:+        pass++    # Check if Electronics editor is active+    is_electronics = False+    try:+        app.executeTextCommand("Electron.run DISPLAY")+        is_electronics = True+    except Exception:+        pass++    # Active document+    active_doc_name = None+    try:+        doc = app.activeDocument+        if doc:+            active_doc_name = doc.name+    except Exception:+        pass++    # Active product type+    product_type = None+    try:+        product = app.activeProduct+        if product:+            product_type = product.productType+    except Exception:+        pass++    # All open documents+    documents = []+    try:+        for i in range(app.documents.count):+            doc = app.documents.item(i)+            doc_info = {+                "name": doc.name,+                "isActive": (doc.name == active_doc_name) if active_doc_name else False,+            }++            # documentType may not exist on all document types+            try:+                doc_info["type"] = _document_type_name(doc.documentType)+            except Exception:+                doc_info["type"] = "unknown"++            # isSaved may not be available on all document types+            try:+                doc_info["isSaved"] = doc.isSaved+            except Exception:+                pass++            # Try to get data file info (cloud save path)+            try:+                df = doc.dataFile+                if df:+                    doc_info["dataFile"] = {+                        "name": df.name,+                        "id": df.id,+                    }+                    try:+                        doc_info["dataFile"]["parentFolder"] = df.parentFolder.name+                    except Exception:+                        pass+            except Exception:+                pass++            documents.append(doc_info)+    except Exception as e:+        documents = [{"error": f"Failed to enumerate documents: {e}"}]++    # Build context-aware hint+    hints = []+    if is_electronics:+        hints.append("Electronics workspace active — fusion_electron_run, fusion_board_info, "+                      "fusion_export_source, fusion_export_eagle_source are available.")+    else:+        hints.append("Not in Electronics workspace. Use fusion_show_2d_board to enter board view, "+                      "or fusion_open_cloud_file to open an electronics project (.fprj).")+    hints.append("Check fusion_window_info for blocking dialogs before running commands.")+    hint = " ".join(hints)++    return {+        "success": True,+        "output": f"{len(documents)} document(s) open, active workspace: {active_workspace}",+        "data": {+            "activeWorkspace": active_workspace,+            "activeDocument": active_doc_name,+            "productType": product_type,+            "isElectronics": is_electronics,+            "documents": documents,+        },+        "_hint": hint,+    }+++def _document_type_name(doc_type) -> str:+    """Convert a DocumentType enum to a readable string."""+    type_map = {+        0: "FusionDesign",+        1: "FusionDesign",  # DesignDocumentType+        2: "Drawing",+        3: "Electronics",+        4: "PCB",+    }+    # The enum value might be an int or an enum object+    try:+        val = int(doc_type)+        return type_map.get(val, f"Unknown({val})")+    except (TypeError, ValueError):+        return str(doc_type)
addin/AdomBridge/commands/assembly_bom.pyadded+140
@@ -0,0 +1,140 @@+"""Structured, kit-aware mechanical assembly BOM (mirrors Fusion's Manage -> BOM).++The electronics `export_bom` only works on an open PCB board. This is its mechanical+counterpart: it walks the active Design assembly and returns a purchasing BOM that+respects the component hierarchy. It recurses through organizational subassemblies but+counts a physical part or a purchased kit/unit ONCE, so hardware modeled INSIDE a kit+(for example a "... with fasteners" bracket, or a bearing/pulley unit) is not+double-counted the way a flat allOccurrences walk would count it.+"""++import csv++import adsk.core+import adsk.fusion+++def _material_name(comp):+    try:+        if comp.material:+            return comp.material.name+    except Exception:+        pass+    try:+        if comp.bRepBodies.count > 0 and comp.bRepBodies.item(0).material:+            return comp.bRepBodies.item(0).material.name+    except Exception:+        pass+    return ""+++def _attr(comp, name):+    try:+        v = getattr(comp, name, "") or ""+        return v.strip()+    except Exception:+        return ""+++def handle_assembly_bom(app: adsk.core.Application, args: dict) -> dict:+    """Return a structured, kit-aware parts list for the active mechanical design.++    args:+      treatAsUnit  optional list of name substrings whose subassemblies are counted once+                   and NOT exploded (default: ["with fasteners"]).+      exclude      optional list of top-level component-name prefixes to skip entirely.+      includePhysicalProperties  optional bool -- add volume_cm3 / mass_kg per line.+      outputPath   optional str -- also write a CSV to this Windows path.+    """+    design = adsk.fusion.Design.cast(app.activeProduct)+    if not design:+        return {"success": False, "error": "No active Fusion Design.",+                "_hint": "Open a mechanical design in the Design workspace, then retry."}++    args = args or {}+    kit = [k.lower() for k in (args.get("treatAsUnit") or ["with fasteners", "with fastener"])]+    exclude = tuple(args.get("exclude") or [])+    include_pp = bool(args.get("includePhysicalProperties", False))++    def is_leaf(comp):+        n = comp.name.lower()+        if any(k in n for k in kit):+            return True+        return comp.bRepBodies.count > 0  # a physical part is a leaf++    parts = {}++    def walk(occs):+        for i in range(occs.count):+            occ = occs.item(i)+            comp = occ.component+            name = comp.name+            if any(name.startswith(e) for e in exclude):+                continue+            children = occ.childOccurrences+            has_children = children is not None and children.count > 0+            if is_leaf(comp):+                row = parts.get(name)+                if row is None:+                    row = {+                        "componentName": name,+                        "partNumber": _attr(comp, "partNumber"),+                        "description": _attr(comp, "description"),+                        "material": _material_name(comp),+                        "quantity": 1,+                        "bodies": comp.bRepBodies.count,+                    }+                    if include_pp:+                        try:+                            pp = comp.getPhysicalProperties(+                                adsk.fusion.CalculationAccuracy.LowCalculationAccuracy)+                            row["volume_cm3"] = round(pp.volume, 4)+                            row["mass_kg"] = round(pp.mass, 6)+                        except Exception:+                            row["volume_cm3"] = None+                            row["mass_kg"] = None+                    parts[name] = row+                else:+                    row["quantity"] += 1+            elif has_children:+                walk(children)++    walk(design.rootComponent.occurrences)+    rows = list(parts.values())++    doc_name = design.rootComponent.name+    try:+        if design.parentDocument:+            doc_name = design.parentDocument.name+    except Exception:+        pass++    out = {+        "success": True,+        "design": doc_name,+        "partCount": len(rows),+        "totalInstances": sum(r["quantity"] for r in rows),+        "treatAsUnit": kit,+        "parts": rows,+    }++    outpath = args.get("outputPath")+    if outpath:+        try:+            cols = ["Part Number", "Part Name", "Description", "Material", "Quantity"]+            if include_pp:+                cols += ["Volume cm3", "Mass kg"]+            with open(outpath, "w", newline="", encoding="utf-8") as f:+                w = csv.writer(f)+                w.writerow(cols)+                for r in rows:+                    line = [r["partNumber"], r["componentName"], r["description"],+                            r["material"], r["quantity"]]+                    if include_pp:+                        line += [r.get("volume_cm3"), r.get("mass_kg")]+                    w.writerow(line)+            out["outputPath"] = outpath+        except Exception as e:+            out["csvError"] = str(e)++    return out
addin/AdomBridge/commands/close_document.pyadded+152
@@ -0,0 +1,152 @@+"""Close document command — close a Fusion 360 document without the save dialog."""++import adsk.core+++def handle_close_document(app: adsk.core.Application, args: dict) -> dict:+    """Close a document in Fusion 360 without triggering the save dialog.++    Args (all optional):+        name: Name of the document to close. If omitted, closes the active document.+        save: If True, save before closing. Default False (discard changes, no dialog).++    This is essential for automation — a normal close triggers a modal save dialog+    that blocks the Fusion main thread and hangs the add-in until the user clicks.+    """+    target_name = args.get("name")+    save_changes = args.get("save", False)++    try:+        if target_name:+            # Find the document by name+            doc = None+            for i in range(app.documents.count):+                d = app.documents.item(i)+                if d.name == target_name:+                    doc = d+                    break+            if doc is None:+                # List available docs for a helpful error+                available = [app.documents.item(i).name for i in range(app.documents.count)]+                return {+                    "success": False,+                    "error": f"Document '{target_name}' not found. Open documents: {available}",+                    "_hint": "Call fusion_document_info to list open documents, or use fusion_close_document with no name to close the active document.",+                }+        else:+            # Close the active document+            doc = app.activeDocument+            if doc is None:+                return {+                    "success": False,+                    "error": "No active document to close.",+                    "_hint": "Call fusion_document_info to check open documents — nothing is currently active.",+                }++        doc_name = doc.name++        # Check if document has unsaved changes (for reporting)+        is_saved = True+        try:+            is_saved = doc.isSaved+        except Exception:+            pass++        # Close the document. Passing False skips the save dialog entirely.+        doc.close(save_changes)++        remaining = app.documents.count+        new_active = None+        try:+            if app.activeDocument:+                new_active = app.activeDocument.name+        except Exception:+            pass++        return {+            "success": True,+            "output": f"Closed '{doc_name}' (save={save_changes}, had_unsaved={'yes' if not is_saved else 'no'}). {remaining} document(s) remaining.",+            "data": {+                "closedDocument": doc_name,+                "savedBeforeClose": save_changes,+                "hadUnsavedChanges": not is_saved,+                "remainingDocuments": remaining,+                "activeDocument": new_active,+            },+            "_hint": f"{remaining} document(s) still open."+                     + (f" Active: '{new_active}'. " if new_active else " No active document. ")+                     + "Use fusion_get_app_state to check workspace, or fusion_open_cloud_file to open another document.",+        }++    except Exception as e:+        return {+            "success": False,+            "error": f"Failed to close document: {e}",+            "_hint": "Retry with {\"save\": false} to discard changes, or call fusion_screenshot_fusion to check for a blocking Save dialog and dismiss it with fusion_send_key.",+        }+++def handle_close_all_documents(app: adsk.core.Application, args: dict) -> dict:+    """Close ALL open documents without save dialogs.++    Closes every open document/tab in Fusion without triggering any save+    dialogs. Essential before restarting Fusion to avoid the 'Recovered+    Documents' modal on next launch.++    Args (all optional):+        save: If True, save each document before closing. Default False.+    """+    save_changes = args.get("save", False)++    closed = []+    errors = []+    skipped = []++    # Snapshot the current document list ONCE. Do NOT loop on app.documents.count,+    # because Fusion may auto-create an Untitled blank doc whenever all docs close,+    # which turns `while count > 0` into an infinite loop and times out the bridge.+    try:+        snapshot = []+        for i in range(app.documents.count):+            d = app.documents.item(i)+            snapshot.append(d)+    except Exception as e:+        return {+            "success": False,+            "error": f"Failed to enumerate documents: {e}",+            "_hint": "Retry with {\"save\": false} to discard changes, or call fusion_screenshot_fusion to check for a blocking Save dialog and dismiss it with fusion_send_key.",+        }++    for doc in snapshot:+        try:+            doc_name = doc.name+        except Exception:+            doc_name = "<unknown>"+        try:+            # Skip Untitled blank docs — Fusion recreates them, closing is pointless+            has_data_file = False+            try:+                has_data_file = doc.dataFile is not None+            except Exception:+                has_data_file = False+            if not has_data_file and doc_name.lower().startswith("untitled"):+                skipped.append(doc_name)+                continue+            doc.close(save_changes)+            closed.append(doc_name)+        except Exception as e:+            errors.append(f"{doc_name}: {e}")+            # Keep going — don't abort the whole batch on one failure++    return {+        "success": len(errors) == 0,+        "output": f"Closed {len(closed)} document(s)"+                  + (f", skipped {len(skipped)} Untitled" if skipped else "")+                  + (f", {len(errors)} error(s)" if errors else ""),+        "data": {+            "closed": closed,+            "skipped": skipped if skipped else None,+            "errors": errors if errors else None,+            "remainingDocuments": app.documents.count,+        },+    }
addin/AdomBridge/commands/cloud_documents.pyadded+1886
@@ -0,0 +1,1886 @@+"""Cloud document management for Fusion 360.++Provides commands to save documents to Autodesk's cloud hub,+list cloud projects and files, and delete cloud files.++Uses the Fusion Data API (app.data) which requires the user+to be signed in to their Autodesk account.++Key concepts:+  - Hub: The team/organization account (e.g., "Adom")+  - Project: A folder-like container in the hub (e.g., "Personal", "Main")+  - DataFolder: Subfolder within a project+  - DataFile: A cloud-stored document with URN, version history, etc.+  - wip_urn: The version-specific URN used by Electronics libraries+             to reference 3D package models (e.g., urn:adsk.wipprod:fs.file:vf.xxx?version=1)+"""++import adsk.core+import adsk.fusion+import os+import threading+import time++# Walk/search progress state — updated by BFS loop on main thread,+# read by health endpoint on HTTP thread.+_walk_progress_lock = threading.Lock()+_walk_progress = None  # None when no walk/search is active+++def get_walk_progress():+    """Return a snapshot of the current walk/search progress, or None."""+    with _walk_progress_lock:+        if _walk_progress is None:+            return None+        return dict(_walk_progress)+++RESOLVE_PROJECT_TIMEOUT = 60  # seconds — overall wall-clock for hub/project enumeration+++def _resolve_project(app, project_name=None):+    """Find a cloud project by name. Defaults to active project.++    Robustness:+      - Every per-hub / per-project access wrapped in try/except so a single+        bad hub or project can't crash the resolve.+      - adsk.doEvents() yields between hubs so the UI stays responsive.+      - Overall wall-clock cap (RESOLVE_PROJECT_TIMEOUT). On expired/trial+        subscriptions the cloud Data API can take 30s+ per hub; cap the+        total so a hung lookup returns an actionable error instead of+        hanging Fusion's main thread indefinitely.+    """+    data = app.data+    if not data:+        return None, "Fusion Data API not available. Are you signed in?"++    if not project_name:+        try:+            proj = data.activeProject+        except Exception as e:+            return None, f"activeProject lookup failed: {e}"+        if proj:+            return proj, None+        return None, "No active project"++    needle = project_name.lower()+    started = time.time()++    # Search all hubs for the named project. Each hub.dataProjects access+    # is a network round-trip on the cloud Data API; wrap in try/except so+    # one bad hub doesn't take down the whole search.+    try:+        hubs = data.dataHubs+        hub_count = hubs.count+    except Exception as e:+        return None, f"Failed to enumerate hubs: {e}"++    for i in range(hub_count):+        if time.time() - started > RESOLVE_PROJECT_TIMEOUT:+            try:+                adsk.core.Application.log(+                    f"AdomBridge: _resolve_project hit timeout ({RESOLVE_PROJECT_TIMEOUT}s) "+                    f"at hub {i}/{hub_count} searching for '{project_name}'"+                )+            except Exception:+                pass+            return None, (+                f"Project lookup timed out after {RESOLVE_PROJECT_TIMEOUT}s "+                f"(searched {i}/{hub_count} hubs). Cloud API may be slow or "+                f"unavailable."+            )+        try:+            hub = hubs.item(i)+        except Exception:+            continue+        try:+            projects = hub.dataProjects+            proj_count = projects.count+        except Exception:+            continue+        for j in range(proj_count):+            try:+                proj = projects.item(j)+                if proj.name.lower() == needle:+                    return proj, None+            except Exception:+                continue+        # Yield between hubs so the UI stays responsive even when the+        # team has many hubs / projects.+        try:+            adsk.doEvents()+        except Exception:+            pass++    return None, f"Project '{project_name}' not found"+++def _resolve_folder(project, folder_path=None):+    """Navigate to a subfolder within a project. Returns root folder if no path given.++    Robustness: each `dataFolders.item(i).name` access is wrapped in+    try/except so a single corrupted subfolder doesn't crash navigation.+    """+    try:+        folder = project.rootFolder+    except Exception as e:+        return None, f"rootFolder lookup failed: {e}"+    if not folder_path:+        return folder, None++    parts = [p.strip() for p in folder_path.replace("\\", "/").split("/") if p.strip()]+    for part in parts:+        needle = part.lower()+        found = False+        try:+            subfolders = folder.dataFolders+            sub_count = subfolders.count+        except Exception as e:+            return None, f"dataFolders lookup failed for '{folder.name}': {e}"+        for i in range(sub_count):+            try:+                sf = subfolders.item(i)+                if sf.name.lower() == needle:+                    folder = sf+                    found = True+                    break+            except Exception:+                continue+        if not found:+            return None, f"Folder '{part}' not found in '{folder.name}'"++    return folder, None+++def handle_save_to_cloud(app: adsk.core.Application, args: dict) -> dict:+    """Save the active Fusion document to the cloud.++    Args:+        args: Dict with:+            - name: Name for the cloud document (required).+            - projectName: Target project name (optional, defaults to active project).+            - folderPath: Subfolder path within the project (optional, defaults to root).+            - description: Document description (optional).+    """+    name = args.get("name", "").strip()+    if not name:+        return {"success": False, "error": "No name specified. Provide a name for the cloud document."}++    doc = app.activeDocument+    if not doc:+        return {+            "success": False,+            "error": "No active document to save.",+            "_hint": "Call fusion_open_cloud_file or fusion_import_file first to have an active document, then retry.",+        }++    project_name = args.get("projectName", "")+    folder_path = args.get("folderPath", "")+    description = args.get("description", "")++    project, err = _resolve_project(app, project_name or None)+    if err:+        return {+            "success": False,+            "error": err,+            "_hint": "Call fusion_list_cloud_projects to see available project names, then retry with a valid projectName.",+        }++    folder, err = _resolve_folder(project, folder_path or None)+    if err:+        return {+            "success": False,+            "error": err,+            "_hint": "Call fusion_list_cloud_files with this projectName to see valid folderPath values, or call fusion_create_cloud_folder to create it.",+        }++    try:+        result = doc.saveAs(name, folder, description, "")+    except Exception as e:+        return {+            "success": False,+            "error": f"saveAs failed: {e}",+            "data": {"hint": "The document may already exist with this name, or you may lack permissions."},+        }++    if not result:+        return {"success": False, "error": "saveAs returned False. The save may have failed."}++    # Collect saved file info+    response_data = {+        "name": name,+        "project": project.name,+        "folder": folder.name,+        "documentName": doc.name,+        "isSaved": doc.isSaved,+    }++    df = doc.dataFile+    if df:+        response_data["fileId"] = df.id+        try:+            response_data["versionId"] = df.versionId+        except Exception:+            pass+        try:+            response_data["versionNumber"] = df.versionNumber+        except Exception:+            pass+        # The wip_urn format used by Electronics libraries for 3D packages+        if df.id and "wipprod" in df.id:+            response_data["wipUrn"] = df.id++    return {+        "success": True,+        "output": f"Saved '{name}' to project '{project.name}'",+        "data": response_data,+    }+++def handle_list_cloud_projects(app: adsk.core.Application, args: dict) -> dict:+    """List all cloud projects in the user's hub(s).++    Robustness (v1.0.2):+      - Per-hub / per-project try/except so a single bad item doesn't kill+        the whole listing.+      - adsk.doEvents() between hubs to keep the UI responsive.+      - Overall wall-clock cap of LIST_PROJECTS_TIMEOUT seconds.+      - Progress logged via Application.log so a slow listing is visible.++    Args:+        args: Dict (no required args).+    """+    data = app.data+    if not data:+        return {+            "success": False,+            "error": "Fusion Data API not available. Are you signed in?",+            "_hint": "Report to the user and ask them to sign into their Autodesk account in Fusion 360, then retry.",+        }++    LIST_PROJECTS_TIMEOUT = 90  # seconds — overall wall-clock cap+    started = time.time()+    list_timed_out = False++    hubs_data = []+    try:+        hubs = data.dataHubs+        hub_count = hubs.count+    except Exception as e:+        return {+            "success": False,+            "error": f"Failed to enumerate hubs: {e}",+            "_hint": "Cloud Data API may be unavailable. Verify sign-in status in Fusion (Help → About / sign-in icon).",+        }++    for i in range(hub_count):+        if time.time() - started > LIST_PROJECTS_TIMEOUT:+            list_timed_out = True+            try:+                adsk.core.Application.log(+                    f"AdomBridge: list_cloud_projects timed out at hub {i}/{hub_count}"+                )+            except Exception:+                pass+            break++        try:+            hub = hubs.item(i)+            hub_name = hub.name+            hub_id = hub.id+        except Exception:+            continue++        try:+            adsk.core.Application.log(+                f"AdomBridge: list_cloud_projects hub [{i+1}/{hub_count}] '{hub_name}'"+            )+        except Exception:+            pass++        projects_list = []+        try:+            projects = hub.dataProjects+            proj_count = projects.count+        except Exception:+            # Couldn't enumerate this hub's projects — still report the hub+            hubs_data.append({"name": hub_name, "id": hub_id, "projects": [], "_error": "dataProjects enumeration failed"})+            continue++        for j in range(proj_count):+            try:+                proj = projects.item(j)+                proj_info = {+                    "name": proj.name,+                    "id": proj.id,+                }+            except Exception:+                continue+            try:+                rf = proj.rootFolder+                if rf:+                    proj_info["rootFolderId"] = rf.id+            except Exception:+                pass+            projects_list.append(proj_info)++        hubs_data.append({+            "name": hub_name,+            "id": hub_id,+            "projects": projects_list,+        })++        # Yield between hubs+        try:+            adsk.doEvents()+        except Exception:+            pass++    # Also note the active project (safely)+    try:+        active_proj = data.activeProject+        active_name = active_proj.name if active_proj else "none"+    except Exception:+        active_name = "(lookup failed)"++    total = sum(len(h["projects"]) for h in hubs_data)+    elapsed = round(time.time() - started, 1)+    return {+        "success": True,+        "output": f"Found {total} projects across {len(hubs_data)} hub(s). Active: {active_name}"+                  f"{' (listing timed out, partial)' if list_timed_out else ''}",+        "data": {+            "activeProject": active_name,+            "hubs": hubs_data,+            "elapsedSeconds": elapsed,+            "listTimedOut": list_timed_out,+        },+        "_hint": "Use fusion_list_cloud_files with a projectName from this list to browse folders. "+                 "Use fusion_walk_cloud_tree for deep recursive search with filters.",+    }+++LIST_FILES_TIMEOUT = 60  # seconds — overall wall-clock cap+++def handle_list_cloud_files(app: adsk.core.Application, args: dict) -> dict:+    """List files in a cloud project/folder.++    Robustness (v1.0.2):+      - Per-file / per-subfolder try/except so a single corrupted item+        doesn't kill the whole listing.+      - adsk.doEvents() every 50 files to keep Fusion's UI responsive on+        folders containing thousands of files.+      - Overall wall-clock cap (LIST_FILES_TIMEOUT). Returns partial+        results with listTimedOut=true instead of hanging.++    Args:+        args: Dict with:+            - projectName: Project name (optional, defaults to active project).+            - folderPath: Subfolder path (optional, defaults to root folder).+    """+    project_name = args.get("projectName", "")+    folder_path = args.get("folderPath", "")++    project, err = _resolve_project(app, project_name or None)+    if err:+        return {+            "success": False,+            "error": err,+            "_hint": "Call fusion_list_cloud_projects to see valid project names.",+        }++    folder, err = _resolve_folder(project, folder_path or None)+    if err:+        return {+            "success": False,+            "error": err,+            "_hint": "Call fusion_list_cloud_files with this projectName to see valid folderPath values.",+        }++    started = time.time()+    list_timed_out = False+    files_skipped = 0+    files_list = []++    try:+        try:+            adsk.core.Application.log(+                f"AdomBridge: list_cloud_files '{folder_path or '(root)'}' in '{project.name}'"+            )+        except Exception:+            pass++        try:+            data_files = folder.dataFiles+            file_count = data_files.count+        except Exception as e:+            return {+                "success": False,+                "error": f"Failed to enumerate files: {e}",+                "_hint": "Call fusion_get_app_state to verify sign-in status; Autodesk cloud session may have expired. If so, the user must sign in via the Fusion UI.",+            }++        for i in range(file_count):+            # Yield every 50 files+            if i > 0 and i % 50 == 0:+                try:+                    adsk.doEvents()+                except Exception:+                    pass+            # Wall-clock cap+            if time.time() - started > LIST_FILES_TIMEOUT:+                list_timed_out = True+                try:+                    adsk.core.Application.log(+                        f"AdomBridge: list_cloud_files hit timeout at file {i}/{file_count}"+                    )+                except Exception:+                    pass+                break++            # Per-item try/except — a single corrupt/deleting file shouldn't+            # break the whole listing.+            try:+                df = data_files.item(i)+            except Exception:+                files_skipped += 1+                continue+            try:+                file_info = {"name": df.name}+            except Exception:+                files_skipped += 1+                continue+            try:+                file_info["id"] = df.id+            except Exception:+                pass+            try:+                file_info["versionNumber"] = df.versionNumber+            except Exception:+                pass+            try:+                file_info["versionId"] = df.versionId+            except Exception:+                pass+            try:+                file_info["fileExtension"] = df.fileExtension+            except Exception:+                pass+            try:+                file_info["dateModified"] = str(df.dateModified)+            except Exception:+                pass+            files_list.append(file_info)+    except Exception as e:+        return {+            "success": False,+            "error": f"Failed to list files: {e}",+            "_hint": "Call fusion_get_app_state to verify sign-in status; Autodesk cloud session may have expired. If so, the user must sign in via the Fusion UI.",+        }++    # Also list subfolders (per-item resilient)+    subfolders = []+    folders_skipped = 0+    try:+        folders = folder.dataFolders+        for i in range(folders.count):+            if time.time() - started > LIST_FILES_TIMEOUT:+                list_timed_out = True+                break+            try:+                sf = folders.item(i)+                subfolders.append({"name": sf.name, "id": sf.id})+            except Exception:+                folders_skipped += 1+                continue+    except Exception:+        pass++    return {+        "success": True,+        "output": f"Found {len(files_list)} files and {len(subfolders)} folders in '{folder.name}' (project: {project.name})"+                  f"{' [listing timed out, partial]' if list_timed_out else ''}",+        "data": {+            "project": project.name,+            "folder": folder.name,+            "files": files_list,+            "subfolders": subfolders,+            "elapsedSeconds": round(time.time() - started, 1),+            "filesSkipped": files_skipped,+            "foldersSkipped": folders_skipped,+            "listTimedOut": list_timed_out,+        },+    }+++def handle_delete_cloud_file(app: adsk.core.Application, args: dict) -> dict:+    """Delete a file from the cloud by name.++    Searches the specified project/folder for the file and deletes it.++    Args:+        args: Dict with:+            - fileName: Name of the file to delete (required).+            - projectName: Project name (optional, defaults to active project).+            - folderPath: Subfolder path (optional, defaults to root folder).+    """+    file_name = args.get("fileName", "").strip()+    file_id = (args.get("fileId") or args.get("lineageUrn") or "").strip()  # PRECISE delete by id+    if not file_name and not file_id:+        return {"success": False, "error": "Provide fileName or fileId (lineage urn for a precise delete)."}++    project_name = args.get("projectName", "")+    folder_path = args.get("folderPath", "")++    project, err = _resolve_project(app, project_name or None)+    if err:+        return {+            "success": False,+            "error": err,+            "_hint": "Call fusion_list_cloud_projects to see valid project names.",+        }++    folder, err = _resolve_folder(project, folder_path or None)+    if err:+        return {+            "success": False,+            "error": err,+            "_hint": "Call fusion_list_cloud_files with this projectName to see valid folderPath values.",+        }++    # Find the file (per-item resilient, with yield + timeout)+    target = None+    started = time.time()+    needle = file_name.lower()+    id_needle = file_id  # exact lineage-urn match when provided (safe in shared folders)+    try:+        try:+            data_files = folder.dataFiles+            file_count = data_files.count+        except Exception as e:+            return {"success": False, "error": f"Failed to enumerate files in '{folder.name}': {e}"}+        for i in range(file_count):+            if i > 0 and i % 50 == 0:+                try:+                    adsk.doEvents()+                except Exception:+                    pass+            if time.time() - started > FIND_FILE_TIMEOUT:+                return {+                    "success": False,+                    "error": f"File lookup timed out after {FIND_FILE_TIMEOUT}s "+                             f"(scanned {i}/{file_count} files in '{folder.name}')",+                    "_hint": "Folder may be too large; provide a more specific folderPath, "+                             "or use fusion_walk_cloud_tree with maxFolders + nameContains.",+                }+            try:+                df = data_files.item(i)+                if id_needle:+                    if df.id == id_needle:+                        target = df+                        break+                elif df.name.lower() == needle:+                    target = df+                    break+            except Exception:+                continue+    except Exception as e:+        return {"success": False, "error": f"Failed to search files: {e}"}++    if not target:+        return {+            "success": False,+            "error": f"File '{file_name}' not found in '{folder.name}' (project: {project.name})",+            "_hint": "Call fusion_walk_cloud_tree to locate the file, or fusion_list_cloud_files to list what's in the folder.",+        }++    file_id = target.id+    try:+        target.deleteMe()+    except Exception as e:+        return {+            "success": False,+            "error": f"Delete failed: {e}",+            "data": {"hint": "You may lack permissions to delete this file."},+        }++    return {+        "success": True,+        "output": f"Deleted '{file_name}' from '{folder.name}' (project: {project.name})",+        "data": {+            "fileName": file_name,+            "fileId": file_id,+            "project": project.name,+            "folder": folder.name,+        },+    }+++def handle_create_cloud_folder(app: adsk.core.Application, args: dict) -> dict:+    """Create a new folder in a cloud project.++    Args:+        args: Dict with:+            - folderName: Name of the folder to create (required).+            - projectName: Target project (optional, defaults to active project).+            - parentPath: Parent folder path (optional, defaults to project root).+    """+    folder_name = args.get("folderName", "").strip()+    if not folder_name:+        return {"success": False, "error": "No folderName specified."}++    project_name = args.get("projectName", "")+    parent_path = args.get("parentPath", "")++    project, err = _resolve_project(app, project_name or None)+    if err:+        return {+            "success": False,+            "error": err,+            "_hint": "Call fusion_list_cloud_projects to see available projects, or fusion_list_cloud_files with a known project name to browse folders.",+        }++    parent, err = _resolve_folder(project, parent_path or None)+    if err:+        return {+            "success": False,+            "error": err,+            "_hint": "Call fusion_list_cloud_projects to see available projects, or fusion_list_cloud_files with a known project name to browse folders.",+        }++    # Check if folder already exists (per-item resilient, with yield + timeout)+    needle = folder_name.lower()+    started = time.time()+    try:+        existing = parent.dataFolders+        existing_count = existing.count+    except Exception as e:+        return {+            "success": False,+            "error": f"Failed to enumerate subfolders of '{parent.name}': {e}",+            "_hint": "Cloud Data API may be unavailable. Verify sign-in status in Fusion.",+        }+    for i in range(existing_count):+        if i > 0 and i % 50 == 0:+            try:+                adsk.doEvents()+            except Exception:+                pass+        if time.time() - started > 30:+            # Don't hang the main thread enumerating a huge subfolder list.+            # If we didn't find a match in 30s, fall through to create — Fusion+            # itself will detect a collision on add().+            break+        try:+            sf = existing.item(i)+            if sf.name.lower() == needle:+                return {+                    "success": True,+                    "output": f"Folder '{folder_name}' already exists in '{parent.name}'",+                    "data": {+                        "folderName": sf.name,+                        "folderId": sf.id,+                        "project": project.name,+                        "parentFolder": parent.name,+                        "alreadyExisted": True,+                    },+                }+        except Exception:+            continue++    try:+        new_folder = parent.dataFolders.add(folder_name)+    except Exception as e:+        return {+            "success": False,+            "error": f"Failed to create folder: {e}",+            "_hint": "Call fusion_get_app_state to verify sign-in status; Autodesk cloud session may have expired. If so, the user must sign in via the Fusion UI.",+        }++    return {+        "success": True,+        "output": f"Created folder '{folder_name}' in '{parent.name}' (project: {project.name})",+        "data": {+            "folderName": new_folder.name,+            "folderId": new_folder.id,+            "project": project.name,+            "parentFolder": parent.name,+        },+    }+++FIND_FILE_TIMEOUT = 60  # seconds — overall wall-clock cap for find+++def _find_cloud_file(app, args):+    """Find a cloud file by name in a project/folder. Returns (dataFile, project, folder, error).++    Robustness (v1.0.2): per-file try/except + doEvents every 50 files + wall-clock cap.+    """+    file_name = args.get("fileName", "").strip()+    if not file_name:+        return None, None, None, "No fileName specified."++    project_name = args.get("projectName", "")+    folder_path = args.get("folderPath", "")++    project, err = _resolve_project(app, project_name or None)+    if err:+        return None, None, None, err++    folder, err = _resolve_folder(project, folder_path or None)+    if err:+        return None, None, None, err++    file_ext = args.get("fileExtension", "").strip().lower().lstrip(".")+    needle = file_name.lower()+    started = time.time()++    target = None+    try:+        try:+            data_files = folder.dataFiles+            file_count = data_files.count+        except Exception as e:+            return None, None, None, f"Failed to enumerate files in '{folder.name}': {e}"++        for i in range(file_count):+            # Yield every 50 files so Fusion UI stays responsive+            if i > 0 and i % 50 == 0:+                try:+                    adsk.doEvents()+                except Exception:+                    pass+            # Wall-clock cap+            if time.time() - started > FIND_FILE_TIMEOUT:+                return None, None, None, (+                    f"File lookup timed out after {FIND_FILE_TIMEOUT}s "+                    f"(scanned {i}/{file_count} files in '{folder.name}'). "+                    f"Folder may be too large; try a more specific folderPath."+                )++            # Per-item try/except+            try:+                df = data_files.item(i)+                df_name = df.name+            except Exception:+                continue++            if df_name.lower() == needle:+                # If extension filter specified, match it+                if file_ext:+                    try:+                        if df.fileExtension.lower().lstrip(".") != file_ext:+                            continue+                    except Exception:+                        continue+                target = df+                break+    except Exception as e:+        return None, None, None, f"Failed to search files: {e}"++    if not target:+        ext_hint = f" with extension '.{file_ext}'" if file_ext else ""+        return None, None, None, f"File '{file_name}'{ext_hint} not found in '{folder.name}' (project: {project.name})"++    return target, project, folder, None+++def handle_check_recovery(app: adsk.core.Application, args: dict) -> dict:+    """Check if a cloud file has a recovery document from a previous crash.++    NOTE: The Fusion Python API does not reliably expose recovery document+    status. This command attempts to check, but may return false negatives.+    The most reliable detection is at the bridge level — if open_cloud_file+    times out, it's likely because a recovery dialog appeared.++    Args:+        fileName: Name of the file to check (required).+        projectName: Project to search in (optional, defaults to active project).+        folderPath: Subfolder path (optional, defaults to root).+    """+    target, project, folder, err = _find_cloud_file(app, args)+    if err:+        return {+            "success": False,+            "error": err,+            "_hint": "Call fusion_list_cloud_projects to see available projects, or fusion_list_cloud_files with a known project name to browse folders.",+        }++    # Try to check for recovery doc — but these API methods may not exist+    has_recovery = False+    try:+        if hasattr(target, 'hasRecoveryDocument'):+            has_recovery = target.hasRecoveryDocument+    except Exception:+        pass++    return {+        "success": True,+        "output": (+            f"Recovery document found for '{target.name}' (API check)."+            if has_recovery+            else f"No recovery document detected for '{target.name}' via API. "+                 "Note: this check is not 100% reliable — Fusion may still show "+                 "a recovery dialog when opening. The bridge will detect this "+                 "via timeout if it happens."+        ),+        "data": {+            "fileName": target.name,+            "fileId": target.id,+            "project": project.name,+            "hasRecovery": has_recovery,+            "apiReliable": hasattr(target, 'hasRecoveryDocument'),+        },+    }+++def _ecad_open_reprimand(app):+    """Detect when an AI opened an electronics CHILD file instead of the PROJECT.++    Electronics files are a parent/child chain: PROJECT (EcadDesignProductType) ->+    schematic (SchematicProductType) -> board/.brd (BoardProductType) -> 3D (the leaf,+    generated from the .brd). Only the PROJECT should be opened directly; its schematic and+    board open from it. Returns a reprimand string for a child file, a confirmation for the+    project, or '' if it cannot tell.+    """+    try:+        pt = app.activeProduct.productType+    except Exception:+        return ''+    if pt == 'EcadDesignProductType':+        return ('OK: opened the electronics PROJECT file (EcadDesignProductType) - correct. '+                'Its schematic, board and 3D are children; switch to them from here.')+    nav = (' Electronics files are a parent/child chain: PROJECT (EcadDesignProductType) ->'+           ' schematic (SchematicProductType) -> board/.brd (BoardProductType) -> 3D (the leaf,'+           ' generated from the .brd). ALWAYS open the PROJECT file; its schematic and board open'+           ' from it. NEVER open a schematic, .brd, or 3D file directly to get the board.')+    label = {'SchematicProductType': 'the SCHEMATIC',+             'BoardProductType': 'the BOARD (.brd) / its 3D PCB',+             'DesignProductType': 'a 3D model file'}.get(pt)+    if label:+        return ('STOP - WRONG FILE: you opened ' + label + ' (' + pt + ') directly, not the project.'+                + nav)+    return ''+++def handle_open_cloud_file(app: adsk.core.Application, args: dict) -> dict:+    """Open a cloud file in Fusion 360 by name.++    PCB/ELECTRONICS NAV RULE: a board is NOT a standalone file - the schematic, 2D board and 3D board are VIEWS inside ONE electronics DESIGN. Open the DESIGN document first (fusion_open_cloud_file or fusion_open_by_urn), THEN switch to its schematic and its 2D board (fusion_show_2d_board) and 3D board (fusion_show_3d_board). A Select-Electronics-Design-File picker IS that design list of its schematic + board. An EMPTY 2D board usually means you opened a derivative or the wrong file, or it is out of sync - reopen the parent electronics DESIGN and switch to its board view; do NOT open a .brd or .sch as a standalone file.++    NOTE: If the file has a recovery document from a previous crash, Fusion+    will show a blocking modal dialog. The bridge layer (server.py) detects+    this via timeout and reports it to the AI. The AI should then screenshot+    and decide how to handle the dialog.++    Args:+        fileName: Name of the file to open (required).+        projectName: Project to search in (optional, defaults to active project).+        folderPath: Subfolder path (optional, defaults to root).+    """+    target, project, folder, err = _find_cloud_file(app, args)+    if err:+        return {+            "success": False,+            "error": err,+            "_hint": "Call fusion_list_cloud_projects to see available projects, or fusion_list_cloud_files with a known project name to browse folders.",+        }++    # Open the file — if a recovery dialog appears, this call will block+    # and the bridge will detect the timeout.+    # Retry on InternalValidationError: Fusion's cloud hub frequently+    # throws this on the first try after a recent close, but the second+    # attempt (with a brief delay) usually succeeds.+    import time+    doc = None+    last_err = None+    attempts = []+    for attempt in range(3):+        try:+            doc = app.documents.open(target)+            if doc:+                break+        except Exception as e:+            last_err = str(e)+            attempts.append(f"attempt {attempt+1}: {last_err}")+            if "InternalValidationError" in last_err and attempt < 2:+                time.sleep(2 + attempt * 2)  # 2s, 4s+                continue+            break++    if not doc:+        return {+            "success": False,+            "error": f"Failed to open '{target.name}' after {len(attempts)} attempts: {last_err}",+            "_hint": "Call fusion_screenshot to check for a recovery dialog or other modal, then fusion_send_key with {\"key\":\"escape\"} or click to dismiss it, then retry.",+            "data": {"fileId": target.id, "attempts": attempts},+        }++    # Explicitly activate the freshly-opened doc. Fusion's cloud hub can+    # auto-reopen recent tabs in the background, stealing focus from the+    # doc we just opened. Force it back.+    activate_note = None+    try:+        doc.activate()+        activate_note = "activated"+    except Exception as e:+        activate_note = f"activate-failed: {e}"++    # Enumerate ALL currently open docs so the caller can see any ghost tabs+    # that Fusion auto-reopened alongside the target.+    open_docs = []+    try:+        for i in range(app.documents.count):+            d = app.documents.item(i)+            df_name = None+            try:+                df_name = d.dataFile.name if d.dataFile else None+            except Exception:+                df_name = None+            open_docs.append({+                "name": d.name,+                "dataFileName": df_name,+                "isActive": (d == app.activeDocument),+            })+    except Exception:+        pass++    # Check whether the now-active doc actually matches the target+    active_matches = False+    try:+        active_df_name = app.activeDocument.dataFile.name if app.activeDocument and app.activeDocument.dataFile else None+        active_matches = (active_df_name == target.name)+    except Exception:+        pass++    response_data = {+        "fileName": target.name,+        "fileId": target.id,+        "project": project.name,+        "documentName": doc.name,+        "activateResult": activate_note,+        "activeMatchesTarget": active_matches,+        "openDocuments": open_docs,+        "ghostTabCount": max(0, len(open_docs) - 1),+    }++    try:+        response_data["versionNumber"] = target.versionNumber+    except Exception:+        pass+    try:+        response_data["fileExtension"] = target.fileExtension+    except Exception:+        pass+    try:+        ws = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+        response_data["activeWorkspace"] = ws+    except Exception:+        pass++    _rep = _ecad_open_reprimand(app)+    return {+        "success": True,+        "output": ((_rep + " || ") if _rep.startswith("STOP") else "") + f"Opened '{target.name}' from project '{project.name}'",+        "_hint": _rep,+        "message": f"Opened '{target.name}'. IMPORTANT: Fusion may show a blocking dialog "+                   f"('What to design?', 'PCB out of date', etc.) that is NOT visible to the API. "+                   f"You MUST screenshot the Fusion window now to verify no dialog is blocking.",+        "data": response_data,+        "postOpenCheck": {+            "required": True,+            "steps": [+                "Run desktop_list_windows to find the Fusion HWND",+                "Run desktop_screenshot_window with that HWND",+                "If a dialog is visible, dismiss it with fusion_send_key {\"key\": \"escape\"} or fusion_click_fusion on the Cancel/X button",+                "Screenshot again to confirm the dialog is gone",+            ],+            "commonDialogs": [+                {"name": "What to design?", "dismiss": "fusion_send_key {\"key\": \"escape\"} or click Cancel"},+                {"name": "PCB out of date", "dismiss": "Click Update or X to dismiss"},+                {"name": "Recovered Documents", "dismiss": "fusion_dismiss_recovery"},+                {"name": "Save changes?", "dismiss": "fusion_send_key {\"key\": \"escape\"} to cancel"},+            ],+        },+    }+++def handle_search_cloud_files(app: adsk.core.Application, args: dict) -> dict:+    """Search for files in a cloud project by name.++    [WARNING - DO NOT USE FOR SEARCH] This goes through Fusion's rate-limited+    add-in Data API. It is SLOW (a real project can take 30+ MINUTES) and CAN+    CRASH the live Fusion session: the add-in connection gets forcibly closed+    (WinError 10054) and Fusion goes down. Use fusion_aps_search instead (APS+    Data Management server-side index - returns in SECONDS). Read the+    'fusion-aps-search' skill before touching this verb. Only fall back here as+    a last resort when APS is unconfigured AND you accept the crash risk.++    Case-insensitive substring match on file names. Searches the root folder+    by default (fast, safe). Set recursive=true to search subfolders — but+    this makes one cloud API call per folder, so use maxDepth and maxFolders+    to stay safe.++    SAFETY (v1.0.1 — May 2026): The previous implementation had thin+    defenses and could freeze Fusion's main thread for long enough that+    Windows marked the window "Not Responding" — users perceived this as+    a crash. The fixes:++      - Per-folder wall-clock timeout (FOLDER_TIMEOUT = 30s). If a single+        folder's cloud calls take >30s we skip the rest of that folder+        and move on, instead of blocking the main thread indefinitely.+      - Overall search wall-clock cap (SEARCH_TIMEOUT = 120s). The whole+        search aborts cleanly with partial results if exceeded.+      - Per-file try/except wrapping `df.name` and `df.fileExtension`+        access. A single corrupt file no longer kills the folder.+      - adsk.doEvents() yields every 50 files (not just per-folder), so+        a folder with thousands of files doesn't starve the UI.+      - adsk.core.Application.log() per-folder progress so post-mortem+        forensics show exactly where the search was at any point.+      - Iterative BFS queue (no recursion). Prevents Python stack growth+        on deep trees.++    Args:+        args: Dict with:+            - query: Search string (required). Matches file names.+            - projectName: Limit search to this project (optional, defaults to active).+            - folderPath: Start search in this subfolder (optional, defaults to root).+            - recursive: Search subfolders (default: false — root only).+            - maxDepth: Max recursion depth (default: 2, no upper cap).+            - maxFolders: Max folders to visit (default: 10, no upper cap).+                          Default is intentionally low — search_cloud_files is+                          tuned for quick targeted lookups. For exhaustive walks+                          across hundreds of folders, prefer fusion_walk_cloud_tree+                          which has a 600s envelope vs search's 120s.+            - maxResults: Max results to return (default: 20, no upper cap).+            - folderTimeout: Per-folder cloud-API timeout in seconds (default: 30).+            - searchTimeout: Overall wall-clock timeout in seconds (default: 120).+                             If you raise this above 180, also pass `timeout:<N>`+                             at the bridge level so the HTTP waiter envelope+                             doesn't give up first.++    Returns data:+        files, totalFound, foldersSearched, foldersSkipped, project, truncated,+        folderLimitReached, searchTimedOut, elapsedSeconds, hint.+    """+    query = args.get("query", "").strip().lower()+    if not query:+        return {"success": False, "error": "No query specified."}++    project_name = args.get("projectName", "")+    folder_path = args.get("folderPath", "")+    recursive = bool(args.get("recursive", False))+    try:+        # No hard upper caps in v1.0.2+ — the per-folder timeout, doEvents+        # yield, per-file try/except, overall search timeout, and stale-lock+        # watchdog all make hard caps unnecessary. You can ask for an+        # exhaustive search of the entire cloud (e.g. maxFolders=10000); the+        # overall timeout governs when partial results are returned.+        max_depth = max(0, int(args.get("maxDepth", 2)))+        max_folders = max(1, int(args.get("maxFolders", 10)))+        max_results = max(1, int(args.get("maxResults", 20)))+    except (TypeError, ValueError):+        return {+            "success": False,+            "error": "maxDepth / maxFolders / maxResults must be integers.",+        }++    # Bounds on cloud-API time. The per-folder timeout protects against a+    # single slow folder. The overall search timeout is the escape hatch.+    # Both are tunable per-call via folderTimeout / searchTimeout args.+    try:+        FOLDER_TIMEOUT = max(5, int(args.get("folderTimeout", 30)))+        SEARCH_TIMEOUT = max(10, int(args.get("searchTimeout", 120)))+    except (TypeError, ValueError):+        FOLDER_TIMEOUT = 30+        SEARCH_TIMEOUT = 120++    # NOTE: the HTTP-server per-command timeout (180s by default for+    # search_cloud_files in http_server.PER_COMMAND_TIMEOUT) is the OUTER+    # envelope. If you set searchTimeout > 180, also pass `timeout`:<N>+    # at the bridge level so the HTTP waiter doesn't give up first. For+    # truly exhaustive walks of huge trees (10+ minutes), prefer+    # fusion_walk_cloud_tree (600s envelope, default maxFolders=500).++    data = app.data+    if not data:+        return {"success": False, "error": "Fusion Data API not available."}++    # Resolve starting point+    if project_name:+        project, err = _resolve_project(app, project_name)+        if err:+            return {+                "success": False,+                "error": err,+                "_hint": "Call fusion_list_cloud_projects to see valid project names.",+            }+    else:+        try:+            project = data.activeProject+        except Exception as e:+            return {"success": False, "error": f"activeProject lookup failed: {e}"}+        if not project:+            return {"success": False, "error": "No active project. Specify projectName."}++    start_folder, err = _resolve_folder(project, folder_path or None)+    if err:+        return {+            "success": False,+            "error": err,+            "_hint": "Call fusion_list_cloud_files with this projectName to see valid folderPath values.",+        }++    results = []+    folders_visited = 0+    folders_skipped = 0+    files_skipped = 0+    search_timed_out = False++    # Set progress state for external observers+    global _walk_progress+    search_start = time.time()+    with _walk_progress_lock:+        _walk_progress = {+            "command": "search_cloud_files",+            "startedAt": search_start,+            "project": project.name,+            "query": query,+            "foldersVisited": 0,+            "currentFolder": folder_path or "(root)",+            "filesFound": 0,+            "elapsedSeconds": 0,+        }++    # Iterative BFS queue: list of (folder, path, depth). No recursion =+    # bounded Python stack depth + easy to short-circuit on timeout.+    start_path = folder_path or ""+    queue = [(start_folder, start_path, 0)]++    try:+        while queue:+            # Overall search timeout — return partial results cleanly.+            if time.time() - search_start > SEARCH_TIMEOUT:+                search_timed_out = True+                try:+                    adsk.core.Application.log(+                        f"AdomBridge: search hit overall timeout ({SEARCH_TIMEOUT}s) "+                        f"after {folders_visited} folder(s), {len(results)} result(s)"+                    )+                except Exception:+                    pass+                break++            # Folder / result caps+            if folders_visited >= max_folders or len(results) >= max_results:+                break++            folder, path, depth = queue.pop(0)+            folders_visited += 1+            folder_start = time.time()++            try:+                adsk.core.Application.log(+                    f"AdomBridge: search [{folders_visited}/{folders_visited + len(queue)}] '{path or '(root)'}' (depth={depth})"+                )+            except Exception:+                pass++            # ── Search files in this folder ──+            try:+                data_files = folder.dataFiles+                # If even getting the dataFiles handle took >FOLDER_TIMEOUT,+                # skip iteration entirely.+                if time.time() - folder_start > FOLDER_TIMEOUT:+                    folders_skipped += 1+                    try:+                        adsk.core.Application.log(+                            f"AdomBridge: search skipping slow folder '{path}' (>{FOLDER_TIMEOUT}s on dataFiles)"+                        )+                    except Exception:+                        pass+                else:+                    file_count = data_files.count+                    for i in range(file_count):+                        # Yield every 50 files to keep Fusion responsive.+                        # Without this, a folder with 1000 files would+                        # block the main thread for the whole iteration.+                        if i > 0 and i % 50 == 0:+                            try:+                                adsk.doEvents()+                            except Exception:+                                pass+                        # Per-file timeout check (cheap).+                        if time.time() - folder_start > FOLDER_TIMEOUT:+                            folders_skipped += 1+                            try:+                                adsk.core.Application.log(+                                    f"AdomBridge: search folder '{path}' hit per-folder timeout at file {i}"+                                )+                            except Exception:+                                pass+                            break+                        if len(results) >= max_results:+                            break++                        # Per-file try/except — a single corrupt or+                        # in-flight-deletion file shouldn't kill the+                        # whole folder. Just skip it and keep going.+                        # We COUNT every skip so the caller knows "0 results"+                        # could be a false negative if files_skipped > 0.+                        try:+                            df = data_files.item(i)+                        except Exception:+                            files_skipped += 1+                            continue+                        try:+                            df_name = df.name+                        except Exception:+                            files_skipped += 1+                            continue+                        if query in df_name.lower():+                            info = {+                                "name": df_name,+                                "project": project.name,+                                "folderPath": path or "/",+                            }+                            try:+                                info["id"] = df.id+                            except Exception:+                                pass+                            try:+                                info["versionNumber"] = df.versionNumber+                            except Exception:+                                pass+                            try:+                                info["fileExtension"] = df.fileExtension+                            except Exception:+                                pass+                            results.append(info)+            except Exception as e:+                folders_skipped += 1+                try:+                    adsk.core.Application.log(+                        f"AdomBridge: search dataFiles error in '{path}': {e}"+                    )+                except Exception:+                    pass++            # Update progress for external observers (health endpoint, bridge)+            with _walk_progress_lock:+                if _walk_progress is not None:+                    _walk_progress["foldersVisited"] = folders_visited+                    _walk_progress["currentFolder"] = path+                    _walk_progress["filesFound"] = len(results)+                    _walk_progress["elapsedSeconds"] = round(time.time() - search_start, 1)+                    _walk_progress["queueSize"] = len(queue)++            # Yield to Fusion's event loop between folders.+            try:+                adsk.doEvents()+            except Exception:+                pass++            # ── Enqueue subfolders ──+            if recursive and depth < max_depth and (time.time() - folder_start <= FOLDER_TIMEOUT):+                try:+                    subfolders = folder.dataFolders+                    sub_count = subfolders.count+                    for i in range(sub_count):+                        if len(results) >= max_results:+                            break+                        try:+                            sf = subfolders.item(i)+                            sub_path = f"{path}/{sf.name}" if path else sf.name+                            queue.append((sf, sub_path, depth + 1))+                        except Exception:+                            continue+                except Exception as e:+                    folders_skipped += 1+                    try:+                        adsk.core.Application.log(+                            f"AdomBridge: search dataFolders error in '{path}': {e}"+                        )+                    except Exception:+                        pass+    finally:+        with _walk_progress_lock:+            _walk_progress = None++    hit_folder_limit = folders_visited >= max_folders+    hit_result_limit = len(results) >= max_results+    elapsed_total = time.time() - search_start++    # ── searchComplete: TRUE only if we exhausted the search space ──+    # Any cap hit OR any skip means we might have missed matches.+    # The AI should treat "0 results + searchComplete=false" as+    # "result unknown", never as "confirmed not present".+    search_complete = (+        not hit_folder_limit+        and not hit_result_limit+        and not search_timed_out+        and folders_skipped == 0+        and files_skipped == 0+    )++    # Cost analysis — useful for both reporting back and informing+    # whether to ask the user for narrower scope next time.+    folders_per_sec = (folders_visited / elapsed_total) if elapsed_total > 0 else 0.0+    cost_analysis = {+        "elapsedSeconds": round(elapsed_total, 1),+        "foldersPerSecond": round(folders_per_sec, 2),+        # Rough estimate based on observed throughput. If the user wanted+        # an exhaustive sweep of the entire project, this is how long it+        # might take given THIS search's average folder latency. (Can't+        # know the project's actual folder count without walking it.)+        "estimatedSecondsPer100Folders": round(100 / folders_per_sec) if folders_per_sec > 0 else None,+    }++    # ── Build a hint that's EXPLICIT about what kind of "0" we got ──+    hint_parts = []++    if search_complete:+        if len(results) == 0:+            hint_parts.append(+                f"COMPLETE SEARCH: searched {folders_visited} folder(s) in "+                f"{round(elapsed_total)}s and found NO files matching '{query}'. "+                f"This is a confirmed negative — the file does not exist in "+                f"'{folder_path or project.name}'."+            )+        else:+            hint_parts.append(+                f"COMPLETE SEARCH: all {len(results)} matches returned."+            )+    else:+        # Search was incomplete — be explicit about WHY and what it implies+        reasons = []+        if hit_folder_limit:+            reasons.append(f"hit maxFolders={max_folders}")+        if hit_result_limit:+            reasons.append(f"hit maxResults={max_results}")+        if search_timed_out:+            reasons.append(f"hit searchTimeout={SEARCH_TIMEOUT}s")+        if folders_skipped > 0:+            reasons.append(f"{folders_skipped} folder(s) errored/timed out")+        if files_skipped > 0:+            reasons.append(f"{files_skipped} file(s) errored on .name access")++        hint_parts.append(+            f"INCOMPLETE SEARCH ({'; '.join(reasons)}). "+            f"Found {len(results)} match(es) in {folders_visited} folder(s) "+            f"over {round(elapsed_total)}s — but this is a LOWER BOUND, not exhaustive."+        )++        if len(results) == 0:+            hint_parts.append(+                "CRITICAL: 0 results does NOT mean the file is absent. The search "+                "stopped before exhausting the scope. Do NOT report 'file not found' "+                "to the user — re-run with broader caps OR narrower folderPath first."+            )++    # ── Proactive scope-narrowing nudge for broad searches ──+    # If this was a wide search and took non-trivial time, the AI should+    # (a) tell the user why this is slow (Autodesk API design, NOT adom-desktop)+    # (b) suggest the simple fix (folderPath narrowing)+    # (c) mention the long-term community fix (paid APS, fork + PR)+    if recursive and not folder_path and elapsed_total > 30:+        cost_str = (+            f" (at the observed {folders_per_sec:.1f} folders/sec, "+            f"a 10-folder subtree would take ~{round(10 / folders_per_sec)}s "+            f"vs this {round(elapsed_total)}s scan)"+            if folders_per_sec > 0 else ""+        )+        hint_parts.append(+            f"BROAD-SCOPE NOTE: searched '{project.name}' from root in "+            f"{round(elapsed_total)}s. WHY SLOW: Autodesk's free Fusion 360 "+            f"Python API has no indexed file-search endpoint, so we must walk "+            f"the cloud Data API one folder at a time — each folder is a "+            f"separate HTTP round-trip to Autodesk. THIS IS AN AUTODESK API "+            f"LIMITATION, NOT AN ADOM-DESKTOP LIMITATION — when you tell the "+            f"user it's slow, attribute it to Autodesk / Fusion 360, not to "+            f"adom-desktop's bridge. Autodesk's PAID Autodesk Platform Services "+            f"(APS, formerly Forge) Data Management API DOES expose indexed "+            f"search that would make this ~instant; if your team has APS "+            f"credentials, you (or anyone in the community) can fork the "+            f"adom-desktop fusion bridge to add an aps_search verb and PR it "+            f"back to https://wiki-ufypy5dpx93o.adom.cloud/apps/adom-desktop "+            f"— the whole Adom community would benefit. FOR THIS SEARCH "+            f"RIGHT NOW: just ask the user 'do you know which subfolder "+            f"<query> is typically stored in?'{cost_str} Naming a folder "+            f"like 'Molecules' cuts search 10-50x with zero new API."+        )+    elif not recursive and len(results) == 0:+        hint_parts.append(+            "Search was limited to root folder (recursive=false). If the file "+            "could be in a subfolder, set recursive=true and ideally folderPath "+            "to the most likely parent (ask the user if unsure)."+        )++    # If we hit the result cap, more matches may exist+    if hit_result_limit:+        hint_parts.append(+            f"RESULT CAP HIT: you got the first {max_results} matches but more "+            f"may exist. Raise maxResults to see all."+        )++    full_hint = " | ".join(hint_parts) if hint_parts else None++    return {+        "success": True,+        "output": f"Found {len(results)} file(s) matching '{query}' "+                  f"(searched {folders_visited} folder(s) in '{project.name}'"+                  f"{', search timed out' if search_timed_out else ''}"+                  f"{', INCOMPLETE' if not search_complete else ''})",+        "data": {+            "query": query,+            "files": results,+            "totalFound": len(results),+            "foldersSearched": folders_visited,+            "foldersSkipped": folders_skipped,+            "filesSkipped": files_skipped,+            "project": project.name,+            "scopeFolderPath": folder_path or "(project root)",+            "recursive": recursive,+            # ── The big flag the AI must check before reporting "no match" ──+            "searchComplete": search_complete,+            "truncated": hit_result_limit,+            "folderLimitReached": hit_folder_limit,+            "searchTimedOut": search_timed_out,+            "elapsedSeconds": round(elapsed_total, 1),+            "costAnalysis": cost_analysis,+            "hint": full_hint,+        },+        "_hint": full_hint,  # also at top level for AI scaffolding that checks _hint+    }+++def handle_export_cloud_file(app: adsk.core.Application, args: dict) -> dict:+    """Export the active Fusion document to a local file for transfer.++    Exports the currently open document as STEP, STL, F3D, or other format+    to a local file path. The file can then be pulled back to Docker via pull_file.++    Args:+        args: Dict with:+            - outputPath: Local file path to export to (required).+            - format: Export format (optional, default "step").+                     Supported: "step", "stl", "f3d", "iges", "sat", "smt".+    """+    output_path = args.get("outputPath", "").strip()+    if not output_path:+        return {"success": False, "error": "No outputPath specified."}++    output_path = output_path.replace("\\", "/")+    fmt = args.get("format", "step").lower().strip()++    doc = app.activeDocument+    if not doc:+        return {+            "success": False,+            "error": "No active document to export.",+            "_hint": "Call fusion_open_cloud_file to open a file, then retry.",+        }++    # Get the design product+    design = None+    try:+        design = adsk.fusion.Design.cast(app.activeProduct)+    except Exception:+        pass++    if not design:+        return {+            "success": False,+            "error": "Active document is not a Fusion Design. Cannot export.",+            "_hint": "Call fusion_activate_workspace with target='design' or open a Fusion Design document first, then retry.",+            "data": {"hint": "Open a design document first, or switch to the Design workspace."},+        }++    # Ensure output directory exists+    out_dir = os.path.dirname(output_path)+    if out_dir and not os.path.exists(out_dir):+        os.makedirs(out_dir, exist_ok=True)++    root = design.rootComponent+    export_mgr = design.exportManager++    try:+        if fmt in ("step", "stp"):+            options = export_mgr.createSTEPExportOptions(output_path, root)+            export_mgr.execute(options)+        elif fmt == "stl":+            options = export_mgr.createSTLExportOptions(root, output_path)+            export_mgr.execute(options)+        elif fmt in ("iges", "igs"):+            options = export_mgr.createIGESExportOptions(output_path, root)+            export_mgr.execute(options)+        elif fmt == "sat":+            options = export_mgr.createSATExportOptions(output_path, root)+            export_mgr.execute(options)+        elif fmt == "smt":+            options = export_mgr.createSMTExportOptions(output_path, root)+            export_mgr.execute(options)+        elif fmt == "f3d":+            options = export_mgr.createFusionArchiveExportOptions(output_path)+            export_mgr.execute(options)+        else:+            return {+                "success": False,+                "error": f"Unsupported format: {fmt}",+                "data": {"supportedFormats": ["step", "stl", "f3d", "iges", "sat", "smt"]},+            }+    except Exception as e:+        return {"success": False, "error": f"Export failed: {e}"}++    if not os.path.exists(output_path):+        return {"success": False, "error": f"Export file was not created at {output_path}"}++    size = os.path.getsize(output_path)++    return {+        "success": True,+        "output": f"Exported '{doc.name}' as {fmt.upper()} to {output_path} ({size} bytes)",+        "data": {+            "outputPath": output_path,+            "format": fmt,+            "fileSize": size,+            "documentName": doc.name,+        },+    }+++def handle_walk_cloud_tree(app: adsk.core.Application, args: dict) -> dict:+    """Walk a cloud folder tree iteratively and return a flat list of all files and folders.++    [WARNING - DO NOT USE FOR SEARCH] Goes through Fusion's rate-limited add-in+    Data API: SLOW (30+ MINUTES on a real project) and CAN CRASH the live Fusion+    session (add-in connection forcibly closed, WinError 10054 - Fusion goes+    down). Use fusion_aps_search instead (APS server-side index, seconds). See+    the 'fusion-aps-search' skill. Last-resort only, when APS is unconfigured+    and you accept the crash risk.++    Purpose: replace the broken recursive search_cloud_files. No sleeps, no tiny+    hardcoded caps. Single add-in call does the whole BFS inside the main thread+    — one request to the bridge, one response back.++    Args:+        args: Dict with:+            - projectName: Project name (optional, defaults to active project).+            - folderPath: Starting folder path (optional, defaults to root).+            - maxDepth: Max recursion depth (optional, default 10).+            - maxFolders: Hard cap on number of folders visited (optional, default 500).+            - extensions: List of file extensions to include, e.g. ["f3d", "fprj"]+                          (optional, default: include all files).+            - nameContains: Substring filter for file/folder names, case-insensitive+                          (optional, default: no filter).+            - includeFiles: If False, return only the folder tree (default True).++    Returns data:+        - project: project name+        - rootFolder: starting folder name+        - folders: [{path, name, id, depth}]+        - files:   [{path, folder, name, id, fileExtension, versionNumber}]+        - stats: {foldersVisited, foldersSkipped, filesFound, maxDepthReached, truncated}+    """+    project_name = args.get("projectName", "") or None+    folder_path = args.get("folderPath", "") or None+    max_depth = int(args.get("maxDepth", 10))+    max_folders = int(args.get("maxFolders", 500))+    extensions = args.get("extensions") or []+    if isinstance(extensions, str):+        extensions = [extensions]+    extensions = {e.lower().lstrip(".") for e in extensions}+    name_contains = (args.get("nameContains") or "").lower()+    include_files = args.get("includeFiles", True)++    project, err = _resolve_project(app, project_name)+    if err:+        return {+            "success": False,+            "error": err,+            "_hint": "Call fusion_list_cloud_projects to see valid project names.",+        }++    root, err = _resolve_folder(project, folder_path)+    if err:+        return {+            "success": False,+            "error": err,+            "_hint": "Call fusion_list_cloud_files with this projectName to see valid folderPath values.",+        }++    folders_out = []+    files_out = []+    folders_visited = 0+    folders_skipped = 0+    files_found = 0+    max_depth_reached = 0+    truncated = False++    # Iterative BFS queue: list of (folder, path, depth)+    start_path = root.name if folder_path else ""+    queue = [(root, start_path, 0)]++    # Set progress state so external callers (health endpoint, bridge busy+    # gate) know a walk is running and can report progress.+    global _walk_progress+    walk_start = time.time()+    with _walk_progress_lock:+        _walk_progress = {+            "command": "walk_cloud_tree",+            "startedAt": walk_start,+            "project": project.name,+            "rootFolder": root.name,+            "foldersVisited": 0,+            "queueSize": len(queue),+            "currentFolder": start_path or "(root)",+            "filesFound": 0,+            "elapsedSeconds": 0,+        }++    try:+        while queue:+            if folders_visited >= max_folders:+                truncated = True+                break++            folder, path, depth = queue.pop(0)+            folders_visited += 1+            if depth > max_depth_reached:+                max_depth_reached = depth++            # Per-folder wall-clock timeout — if a single folder's cloud API+            # calls take >30s, skip remaining work and move on. We can't+            # interrupt folder.dataFiles mid-call, but we can skip subfolder+            # enumeration and file iteration if the first call was too slow.+            FOLDER_TIMEOUT = 30  # seconds+            folder_start = time.time()++            adsk.core.Application.log(+                f"AdomBridge: walk [{folders_visited}/{folders_visited + len(queue)}] '{path}'"+            )++            folders_out.append({+                "path": path,+                "name": folder.name,+                "id": folder.id,+                "depth": depth,+            })++            # List files in this folder+            if include_files:+                try:+                    data_files = folder.dataFiles+                    if time.time() - folder_start > FOLDER_TIMEOUT:+                        adsk.core.Application.log(+                            f"AdomBridge: walk skipping slow folder '{path}' (>{FOLDER_TIMEOUT}s on dataFiles)"+                        )+                        folders_skipped += 1+                    else:+                        for i in range(data_files.count):+                            # Yield every 50 files to keep Fusion responsive+                            if i > 0 and i % 50 == 0:+                                try:+                                    adsk.doEvents()+                                except Exception:+                                    pass+                            if time.time() - folder_start > FOLDER_TIMEOUT:+                                adsk.core.Application.log(+                                    f"AdomBridge: walk folder '{path}' hit timeout during file iteration at file {i}"+                                )+                                folders_skipped += 1+                                break+                            try:+                                df = data_files.item(i)+                                name = df.name+                                ext = ""+                                try:+                                    ext = (df.fileExtension or "").lower()+                                except Exception:+                                    pass+                                if extensions and ext not in extensions:+                                    continue+                                if name_contains and name_contains not in name.lower():+                                    continue+                                entry = {+                                    "path": (path + "/" + name) if path else name,+                                    "folder": path,+                                    "name": name,+                                    "id": df.id,+                                    "fileExtension": ext,+                                }+                                try:+                                    entry["versionNumber"] = df.versionNumber+                                except Exception:+                                    pass+                                files_out.append(entry)+                                files_found += 1+                            except Exception:+                                continue+                except Exception:+                    folders_skipped += 1++            # Enqueue subfolders (unless at depth limit or folder timed out)+            if depth < max_depth and (time.time() - folder_start <= FOLDER_TIMEOUT):+                try:+                    subfolders = folder.dataFolders+                    for i in range(subfolders.count):+                        try:+                            sf = subfolders.item(i)+                            sub_path = (path + "/" + sf.name) if path else sf.name+                            queue.append((sf, sub_path, depth + 1))+                        except Exception:+                            continue+                except Exception:+                    folders_skipped += 1+            elif depth < max_depth:+                adsk.core.Application.log(+                    f"AdomBridge: walk skipping subfolders of '{path}' (folder timed out)"+                )++            # Update progress for external observers (health endpoint, bridge)+            with _walk_progress_lock:+                if _walk_progress is not None:+                    _walk_progress["foldersVisited"] = folders_visited+                    _walk_progress["queueSize"] = len(queue)+                    _walk_progress["currentFolder"] = path+                    _walk_progress["filesFound"] = files_found+                    _walk_progress["elapsedSeconds"] = round(time.time() - walk_start, 1)++            # Yield to Fusion's event loop to prevent "Not Responding" state.+            try:+                adsk.doEvents()+            except Exception:+                pass++    finally:+        with _walk_progress_lock:+            _walk_progress = None++    summary = (+        f"Walked {folders_visited} folders under '{root.name}' in project '{project.name}' "+        f"(max depth {max_depth_reached}). Found {files_found} files."+    )+    if truncated:+        summary += f" TRUNCATED at maxFolders={max_folders} — increase limit or narrow folderPath."++    return {+        "success": True,+        "output": summary,+        "data": {+            "project": project.name,+            "rootFolder": root.name,+            "folders": folders_out,+            "files": files_out,+            "stats": {+                "foldersVisited": folders_visited,+                "foldersSkipped": folders_skipped,+                "filesFound": files_found,+                "maxDepthReached": max_depth_reached,+                "truncated": truncated,+            },+        },+    }+++def handle_open_by_urn(app: adsk.core.Application, args: dict) -> dict:+    """Open a cloud file directly by its APS/Fusion URN.++    PCB/ELECTRONICS NAV RULE: a board is NOT a standalone file - the schematic, 2D board and 3D board are VIEWS inside ONE electronics DESIGN. Open the DESIGN document first (fusion_open_cloud_file or fusion_open_by_urn), THEN switch to its schematic and its 2D board (fusion_show_2d_board) and 3D board (fusion_show_3d_board). A Select-Electronics-Design-File picker IS that design list of its schematic + board. An EMPTY 2D board usually means you opened a derivative or the wrong file, or it is out of sync - reopen the parent electronics DESIGN and switch to its board view; do NOT open a .brd or .sch as a standalone file.++    Works for ANY file regardless of folder nesting (unlike open_cloud_file,+    which searches by name only in a project's root folder). APS hands the+    bridge the exact file URN; we resolve it to a Fusion DataFile via+    Data.findFileById and open it.+    """+    urn = (args.get("urn") or args.get("fileUrn") or "").strip()+    if not urn:+        return {"success": False, "error": "No urn specified."}++    # File-based breadcrumb (Application.log only reaches the in-app Text Commands+    # palette, which is unreadable headless). Opening a heavy assembly or an+    # electronics/PCB design can hard-crash the host mid-open with no other trace;+    # this leaves the last step on disk so the crash point is provable afterward.+    import os as _os, tempfile as _tf+    _crumb_path = _os.path.join(_tf.gettempdir(), "adom_open_by_urn.log")+    def _crumb(msg):+        try:+            with open(_crumb_path, "a", encoding="utf-8") as _fh:+                _fh.write(msg + "\n")+                _fh.flush()+        except Exception:+            pass+        try:+            adsk.core.Application.log("[open_by_urn] " + msg)+        except Exception:+            pass++    data = app.data+    # APS returns a version urn like urn:adsk.wipprod:fs.file:vf.<base>?version=N.+    # findFileById wants the file/lineage id — try several derivations.+    raw = urn.split("?")[0]+    candidates = [urn, raw]+    if "fs.file:vf." in raw:+        base = raw.split("fs.file:vf.")[-1]+        candidates.append("urn:adsk.wipprod:dm.lineage:" + base)+        candidates.append(base)++    _crumb("resolving urn: " + urn[:80])++    df = None+    tried = []+    for cid in candidates:+        try:+            f = data.findFileById(cid)+            if f:+                df = f+                tried.append(cid[:55] + " -> FOUND")+                break+            tried.append(cid[:55] + " -> none")+        except Exception as e:+            tried.append(cid[:55] + " -> " + str(e)[:40])+    if not df:+        _crumb("FAILED to resolve urn to a DataFile. tried=" + " | ".join(tried))+        return {"success": False,+                "error": "Could not resolve the file URN to a Fusion DataFile.",+                "_hint": "URN resolution failed — an open-path issue, NOT the Fusion license. A "+                         "read-only/expired/trial Fusion still opens+views files (only save/export "+                         "are blocked). Check the urn form / file access.",+                "data": {"tried": tried, "urn": urn}}++    _crumb("resolved '%s' (id=%s) — about to call documents.open "+           "(PCB/electronics designs spin up the Electronics editor here; a heavy "+           "assembly downloads all referenced parts here — the wedge/crash point)"+           % (df.name, df.id))++    doc = None+    last_err = None+    for attempt in range(3):+        try:+            doc = app.documents.open(df)+            if doc:+                _crumb("documents.open returned a doc for '%s'" % df.name)+                break+        except Exception as e:+            last_err = str(e)+            if "InternalValidationError" in last_err and attempt < 2:+                time.sleep(2 + attempt * 2)+                continue+            break+    if not doc:+        return {"success": False, "error": "Open failed for '%s': %s" % (df.name, last_err),+                "_hint": "documents.open failed — an open-path issue, NOT the Fusion license. A "+                         "read-only/expired/trial Fusion still opens+views files (only save/export "+                         "are blocked). Likely a slow/large assembly, a blocking Electronics picker, "+                         "or a transient cloud error — retry / check fusion_window_info for a modal.",+                "data": {"fileName": df.name, "fileId": df.id}}+    try:+        doc.activate()+    except Exception:+        pass+    _rep = _ecad_open_reprimand(app)+    return {"success": True, "output": ((_rep + " || ") if _rep.startswith("STOP") else "") + ("Opened '%s'." % df.name),+            "_hint": _rep,+            "data": {"fileName": df.name, "fileId": df.id, "resolved": tried}}
addin/AdomBridge/commands/design_info.pyadded+98
@@ -0,0 +1,98 @@+"""Design info command — component tree, bodies, document info."""++import adsk.core+import adsk.fusion+++def handle_get_design_info(app: adsk.core.Application, args: dict) -> dict:+    """Get information about the active design.++    Returns component tree, bodies, user parameters, and document info.+    """+    product = app.activeProduct+    if not product or product.productType != "DesignProductType":+        return {+            "success": False,+            "error": "No active design open in Fusion 360",+            "_hint": "Call fusion_open_cloud_file to open a Design document, or fusion_show_3d_board if an electronics board is open, then retry.",+        }++    design = adsk.fusion.Design.cast(product)+    doc = app.activeDocument++    root = design.rootComponent+    components = _walk_component(root)++    # User parameters+    params = []+    for i in range(design.userParameters.count):+        param = design.userParameters.item(i)+        params.append({+            "name": param.name,+            "expression": param.expression,+            "value": param.value,+            "unit": param.unit,+        })++    return {+        "success": True,+        "data": {+            "document": {+                "name": doc.name if doc else "Untitled",+                "isSaved": doc.isSaved if doc else False,+            },+            "designType": "Parametric" if design.designType == adsk.fusion.DesignTypes.ParametricDesignType else "Direct",+            "components": components,+            "userParameters": params,+        },+    }+++def _walk_component(comp: adsk.fusion.Component) -> dict:+    """Recursively walk a component and its children."""+    bodies = []+    for i in range(comp.bRepBodies.count):+        body = comp.bRepBodies.item(i)+        bodies.append({+            "name": body.name,+            "isVisible": body.isVisible,+            "isSolid": body.isSolid,+            "volume_cm3": body.volume if body.isSolid else None,+        })++    # Also check mesh bodies (STL/3MF imports create these)+    mesh_bodies = []+    try:+        for i in range(comp.meshBodies.count):+            mb = comp.meshBodies.item(i)+            mesh_bodies.append({+                "name": mb.name,+                "isVisible": mb.isVisible,+            })+    except Exception:+        pass  # meshBodies may not exist in older API versions++    children = []+    for i in range(comp.occurrences.count):+        occ = comp.occurrences.item(i)+        children.append({+            "name": occ.name,+            "isVisible": occ.isVisible,+            "component": _walk_component(occ.component),+        })++    result = {+        "name": comp.name,+        "bodies": bodies,+        "children": children,+    }+    if mesh_bodies:+        result["meshBodies"] = mesh_bodies++    # Debug info: feature count tells us if there's actual content+    try:+        result["features"] = comp.features.count+    except Exception:+        pass++    return result
addin/AdomBridge/commands/document_info.pyadded+305
@@ -0,0 +1,305 @@+"""Document info and activation commands.++document_info — lightweight metadata about ALL open documents plus active doc details.+activate_document — switch to a specific open document tab by name or type.+"""++import adsk.core+++def _document_type_str(doc_type) -> str:+    """Convert a DocumentType enum to a human-readable string."""+    if doc_type is None:+        return "unknown"+    type_map = {+        0: "FusionDesign",+        1: "FusionDesign",+        2: "Drawing",+        3: "Electronics",+        4: "PCB",+    }+    try:+        val = int(doc_type)+        return type_map.get(val, f"Unknown({val})")+    except (TypeError, ValueError):+        return str(doc_type)+++def handle_document_info(app: adsk.core.Application, args: dict) -> dict:+    """Get metadata about all open documents and the active document.++    Returns every open document/tab with name, type, and active status,+    plus detailed cloud info for the active document. Uses only in-memory+    data — no cloud API calls.++    This is the command to use when Claude needs to know what tabs are open+    and which one is focused, without expensive cloud searches.+    """+    # Active workspace+    active_workspace = "unknown"+    try:+        ws = app.executeTextCommand("DebugCommands.ActiveWorkspace")+        if ws:+            active_workspace = ws.strip()+    except Exception:+        pass++    # Active document name (for isActive flag)+    active_doc_name = None+    active_doc = None+    try:+        active_doc = app.activeDocument+        if active_doc:+            active_doc_name = active_doc.name+    except Exception:+        pass++    # Enumerate ALL open documents+    open_documents = []+    try:+        for i in range(app.documents.count):+            doc = app.documents.item(i)+            doc_info = {+                "name": doc.name,+                "isActive": (doc.name == active_doc_name) if active_doc_name else False,+            }+            try:+                doc_info["documentType"] = _document_type_str(getattr(doc, 'documentType', None))+                doc_info["documentTypeRaw"] = str(getattr(doc, 'documentType', None))+            except Exception:+                doc_info["documentType"] = "unknown"++            try:+                doc_info["isSaved"] = doc.isSaved+            except Exception:+                pass++            # Cloud file info (lightweight — just the cached ID)+            try:+                df = doc.dataFile+                if df:+                    doc_info["cloudFileId"] = df.id+                    doc_info["isCloudDocument"] = True+                    try:+                        doc_info["cloudProjectName"] = df.parentProject.name+                    except Exception:+                        pass+                else:+                    doc_info["isCloudDocument"] = False+            except Exception:+                doc_info["isCloudDocument"] = False++            open_documents.append(doc_info)+    except Exception as e:+        open_documents = [{"error": f"Failed to enumerate documents: {e}"}]++    # Detailed info for the active document+    active_detail = {}+    if active_doc:+        try:+            active_detail["documentName"] = active_doc.name+        except Exception:+            pass++        try:+            df = active_doc.dataFile+            if df:+                active_detail["isCloudDocument"] = True+                try:+                    active_detail["cloudFileId"] = df.id+                except Exception:+                    pass+                try:+                    active_detail["documentVersion"] = df.versionNumber+                except Exception:+                    pass+                try:+                    active_detail["cloudProjectName"] = df.parentProject.name+                except Exception:+                    pass+                try:+                    # Build folder path+                    folder = df.parentFolder+                    parts = []+                    depth = 0+                    while folder and depth < 10:+                        parts.append(folder.name)+                        try:+                            folder = folder.parentFolder+                        except Exception:+                            break+                        depth += 1+                    if parts:+                        parts.reverse()+                        active_detail["cloudFolderPath"] = "/".join(parts)+                except Exception:+                    pass+            else:+                active_detail["isCloudDocument"] = False+        except Exception:+            active_detail["isCloudDocument"] = False++        try:+            active_detail["isSaved"] = active_doc.isSaved+        except Exception:+            pass++    # Product type+    try:+        product = app.activeProduct+        if product:+            active_detail["productType"] = product.productType+    except Exception:+        pass++    data = {+        "activeWorkspace": active_workspace,+        "activeDocument": active_doc_name,+        "openDocuments": open_documents,+        "openDocumentCount": len(open_documents),+        **active_detail,+    }++    return {+        "success": True,+        "output": f"{len(open_documents)} document(s) open, "+                  f"active: {active_doc_name or '(none)'}, "+                  f"workspace: {active_workspace}",+        "data": data,+        "_hint": "Use fusion_get_app_state to check workspace type. "+                 "For exports: fusion_export_gerbers, fusion_export_bom, fusion_export_cpl, "+                 "fusion_export_source (.fsch/.fbrd), fusion_export_eagle_source (.sch/.brd). "+                 "Use fusion_activate_document to switch tabs.",+    }+++def handle_activate_document(app: adsk.core.Application, args: dict) -> dict:+    """Switch to a specific open document tab by name or type.++    Searches all open documents and activates the matching one. This is+    essential for automation — Claude can switch between schematic, board,+    and library tabs without asking the user to click.++    Args:+        name: Document name to activate (case-insensitive substring match).+        documentType: Document type to activate — "Electronics", "PCB",+                      "FusionDesign", "Drawing". If both name and type are+                      given, both must match.++    If multiple documents match, activates the first match and lists all+    matches in the response so Claude can refine.+    """+    target_name = args.get("name", "").strip().lower()+    target_type = args.get("documentType", "").strip().lower()+    target_data_file = args.get("dataFileName", "").strip()  # EXACT match on dataFile.name++    if not target_name and not target_type and not target_data_file:+        return {+            "success": False,+            "error": "Specify 'name' (substring) or 'dataFileName' (exact cloud-file name) "+                     "or 'documentType' (Electronics, PCB, FusionDesign, Drawing).",+            "_hint": "Call fusion_document_info to list open documents by index, or fusion_open_cloud_file to open a new document, then retry.",+        }++    # Find matching documents+    matches = []+    try:+        for i in range(app.documents.count):+            doc = app.documents.item(i)+            name_match = True+            type_match = True+            datafile_match = True++            if target_data_file:+                df_name = None+                try:+                    df_name = doc.dataFile.name if doc.dataFile else None+                except Exception:+                    df_name = None+                datafile_match = (df_name == target_data_file)++            if target_name:+                name_match = target_name in doc.name.lower()++            if target_type:+                doc_type_str = _document_type_str(getattr(doc, 'documentType', None)).lower()+                doc_type_raw = str(getattr(doc, 'documentType', None)).lower()+                type_match = (target_type in doc_type_str or+                              target_type in doc_type_raw)++            if name_match and type_match and datafile_match:+                matches.append(doc)+    except Exception as e:+        return {+            "success": False,+            "error": f"Failed to enumerate documents: {e}",+            "_hint": "Call fusion_get_app_state to check if Fusion is in a usable state; a modal dialog may be blocking.",+        }++    if not matches:+        # List what IS open for debugging+        available = []+        try:+            for i in range(app.documents.count):+                doc = app.documents.item(i)+                available.append({+                    "name": doc.name,+                    "type": _document_type_str(getattr(doc, 'documentType', None)),+                })+        except Exception:+            pass++        return {+            "success": False,+            "error": f"No open document matching name='{target_name or '*'}' "+                     f"type='{target_type or '*'}'",+            "_hint": "Call fusion_document_info to list open documents by index, or fusion_open_cloud_file to open a new document, then retry.",+            "data": {+                "openDocuments": available,+                "hint": "Use fusion_document_info to see all open documents.",+            },+        }++    # Activate the first match+    target_doc = matches[0]+    try:+        activated = target_doc.activate()+    except Exception as e:+        return {+            "success": False,+            "error": f"Failed to activate '{target_doc.name}': {e}",+            "_hint": "Call fusion_get_app_state to check if Fusion is in a usable state; a modal dialog may be blocking.",+            "data": {"hint": "The document may be in a state that prevents activation."},+        }++    # Query workspace after activation+    new_workspace = "unknown"+    try:+        ws = app.executeTextCommand("DebugCommands.ActiveWorkspace")+        if ws:+            new_workspace = ws.strip()+    except Exception:+        pass++    response = {+        "success": True,+        "output": f"Activated '{target_doc.name}' — workspace: {new_workspace}",+        "data": {+            "activatedDocument": target_doc.name,+            "documentType": _document_type_str(getattr(target_doc, 'documentType', None)),+            "activeWorkspace": new_workspace,+        },+    }++    # If multiple matches, list them all so Claude can refine+    if len(matches) > 1:+        response["data"]["allMatches"] = [+            {"name": m.name, "type": _document_type_str(getattr(m, 'documentType', None))}+            for m in matches+        ]+        response["data"]["hint"] = (+            f"{len(matches)} documents matched — activated the first one. "+            "Use a more specific name to target a different one."+        )++    return response
addin/AdomBridge/commands/electron_view.pyadded+139
@@ -0,0 +1,139 @@+"""Video-friendly view control for the Fusion Electronics (EAGLE) editor.++One bridge call = a whole smooth motion, because the loop runs HERE inside the add-in+(tight timing + a repaint per frame), not as N round-trips from the bridge server.++  fusion_electron_zoom   - smooth zoom in/out (or fit)+  fusion_electron_pan    - smooth pan/zoom to a board-coordinate box+  fusion_electron_select - select a part by name (or x/y) and surface its properties++All EAGLE motion is `app.executeTextCommand("Electron.run WINDOW ...")`; each frame is+forced to render with `Electron.ImmediateRepaint /full` (the 2D analogue of vp.refresh()).+"""++import time+import adsk.core++# Last view box we set, in board mm (x1, y1, x2, y2). Lets pan interpolate from where+# the view actually is. None until the first pan establishes it.+_view_box = None+++def _run(app, eagle_cmd):+    return app.executeTextCommand(f"Electron.run {eagle_cmd}")+++def _repaint(app):+    try:+        app.executeTextCommand("Electron.ImmediateRepaint /full")+    except Exception:+        pass+++def handle_electron_zoom(app: adsk.core.Application, args: dict) -> dict:+    """Smoothly zoom the schematic / 2D board view.++    Args:+        fit:          bool - zoom to fit the whole sheet/board (ignores factor).+        factor:       float - total zoom multiple (>1 = in, <1 = out). Default 2.0.+        steps:        int   - frames over which to ramp (smoothness). Default 16.+        frameDelayMs: int   - ms between frames. Default 35.+    """+    if args.get("fit"):+        _run(app, "WINDOW FIT")+        _repaint(app)+        return {"success": True, "output": "Zoomed to fit."}++    factor = float(args.get("factor", 2.0))+    steps = max(1, int(args.get("steps", 16)))+    delay = float(args.get("frameDelayMs", 35)) / 1000.0+    per = factor ** (1.0 / steps)  # geometric per-frame step -> perceptually even+    for _ in range(steps):+        _run(app, f"WINDOW {per:.5f}")+        _repaint(app)+        adsk.doEvents()+        time.sleep(delay)+    return {+        "success": True,+        "output": f"Zoomed {'in' if factor > 1 else 'out'} {factor}x over {steps} frames.",+    }+++def handle_electron_pan(app: adsk.core.Application, args: dict) -> dict:+    """Smoothly pan + zoom the view to frame a board-coordinate box.++    Coords are board millimetres (get part positions from fusion_board_info). The view+    animates from wherever it last was (tracked) to the target box.++    Args:+        x1, y1, x2, y2: required floats - the target rectangle (board mm).+        steps:          int   - frames. Default 16.+        frameDelayMs:   int   - ms between frames. Default 35.+    """+    global _view_box+    try:+        tx1, ty1 = float(args["x1"]), float(args["y1"])+        tx2, ty2 = float(args["x2"]), float(args["y2"])+    except (KeyError, TypeError, ValueError):+        return {"success": False, "error": "Need x1,y1,x2,y2 (board mm). Get part positions from fusion_board_info."}++    steps = max(1, int(args.get("steps", 16)))+    delay = float(args.get("frameDelayMs", 35)) / 1000.0++    if _view_box is None:+        _run(app, f"WINDOW ({tx1:.3f} {ty1:.3f}) ({tx2:.3f} {ty2:.3f})")+        _repaint(app)+        _view_box = (tx1, ty1, tx2, ty2)+        return {"success": True, "output": "Framed region (no animation - first view set; later pans animate).",+                "data": {"box": _view_box}}++    sx1, sy1, sx2, sy2 = _view_box+    for i in range(1, steps + 1):+        t = i / steps+        x1 = sx1 + (tx1 - sx1) * t+        y1 = sy1 + (ty1 - sy1) * t+        x2 = sx2 + (tx2 - sx2) * t+        y2 = sy2 + (ty2 - sy2) * t+        _run(app, f"WINDOW ({x1:.3f} {y1:.3f}) ({x2:.3f} {y2:.3f})")+        _repaint(app)+        adsk.doEvents()+        time.sleep(delay)+    _view_box = (tx1, ty1, tx2, ty2)+    return {"success": True,+            "output": f"Panned to ({tx1:.1f},{ty1:.1f})-({tx2:.1f},{ty2:.1f}) over {steps} frames.",+            "data": {"box": _view_box}}+++def handle_electron_select(app: adsk.core.Application, args: dict) -> dict:+    """Select a part (by reference designator, or by x/y board coords) and read its+    properties - the way clicking a part in the editor reveals the properties panel.++    Args:+        name (or component): str - reference designator (e.g. "R1"). Cleanest.+        x, y:                floats - board-mm point to click/select (alternative).+        properties:          bool - also return the selected device's info. Default true.+    """+    name = args.get("name") or args.get("component")+    try:+        if name:+            sel = app.executeTextCommand(f"Electron.SelectbyName {name}")+        elif "x" in args and "y" in args:+            app.executeTextCommand(f"Electron.LeftButtonDown {args['x']} {args['y']}")+            sel = app.executeTextCommand(f"Electron.Select {args['x']} {args['y']}")+        else:+            return {"success": False, "error": "Provide {name} (reference designator) or {x,y} (board mm)."}+    except Exception as e:+        return {"success": False, "error": f"Select failed: {e}"}++    _repaint(app)+    info = ""+    if args.get("properties", True):+        try:+            info = app.executeTextCommand("Electron.sch_get_deviceinfo")+        except Exception:+            pass+    return {+        "success": True,+        "output": f"Selected {name or (str(args.get('x')) + ',' + str(args.get('y')))}.",+        "data": {"selection": str(sel)[:300], "deviceInfo": str(info)[:600]},+    }
addin/AdomBridge/commands/electronics.pyadded+1058
@@ -0,0 +1,1058 @@+"""Electronics commands — run EAGLE commands via Electron.run text command.++Fusion 360's Electronics workspace (inherited from EAGLE) has no Python API,+but we can use `app.executeTextCommand('Electron.run <cmd>')` to send EAGLE+editor commands into the electronics workspace.++IMPORTANT: The user must be in an Electronics editor (schematic, board, or library)+for Electron.run commands to work. The "Electronics Design" overview/container+workspace does NOT count — the user must have a schematic or board open and active.++Workspace hierarchy:+  "Design"              — Normal 3D CAD (Electron.run fails)+  "Electronics Design"  — Container/overview (Electron.run fails)+  "Schematic Editor"    — Schematic editing (Electron.run works)+  "Board Layout"        — PCB layout editing (Electron.run works)+  "Electronics Library" — Library editing (Electron.run works)++Commands that BLOCK (open dialogs — avoid from automation):+  WRITE               — Opens Save As dialog+  ADD                 — Opens component picker dialog+  SHOW <name>         — Opens interactive highlight mode+  GRID (no params)    — Opens grid settings dialog+  EDIT <new>.sym      — Opens "Create new?" confirmation dialog++Safe automation patterns:+  SCRIPT '<path>.scr' — Runs batch commands from file (non-interactive)+  EXPORT SCRIPT       — Exports library/schematic to .scr file (for verification)+  DISPLAY             — Shows/hides layers (non-interactive)+  WINDOW FIT          — Zoom to fit+  EDIT <existing>.sym — Opens existing symbol (no dialog)+  SET CONFIRM YES     — In .scr: suppresses create-new confirmations+"""++import adsk.core+import glob+import os+import re+import tempfile+++def _get_fusion_log_path() -> str | None:+    """Find the latest Fusion 360 log file."""+    log_dir = os.path.join(+        os.environ.get("LOCALAPPDATA", ""),+        "Autodesk", "Autodesk Fusion 360",+    )+    # Find user-specific log dir (e.g. X3G293QFLPJERKGZ/logs/)+    for entry in os.listdir(log_dir):+        candidate = os.path.join(log_dir, entry, "logs")+        if os.path.isdir(candidate):+            logs = sorted(glob.glob(os.path.join(candidate, "AppLogFile*.log")),+                          key=os.path.getmtime, reverse=True)+            if logs:+                return logs[0]+    return None+++def _get_log_line_count(log_path: str) -> int:+    """Get current line count of a log file (fast — seeks to end)."""+    try:+        with open(log_path, "r", encoding="utf-8", errors="replace") as f:+            return sum(1 for _ in f)+    except Exception:+        return 0+++def _check_log_for_alerts(log_path: str, after_line: int) -> list[str]:+    """Check Fusion log for 'New Alert message' entries after a given line number.++    Returns list of alert message texts (the error toast content).+    """+    alerts = []+    try:+        with open(log_path, "r", encoding="utf-8", errors="replace") as f:+            for i, line in enumerate(f, 1):+                if i <= after_line:+                    continue+                if "New Alert message" in line:+                    # Extract: "Tooltip: <msg>, Short Message: <msg>"+                    m = re.search(r"Short Message:\s*(.+?)(?:,\s*Long Message:|$)", line)+                    if m:+                        alerts.append(m.group(1).strip())+                    else:+                        # Fallback: grab everything after "Tooltip: "+                        m2 = re.search(r"Tooltip:\s*(.+?)(?:,|$)", line)+                        if m2:+                            alerts.append(m2.group(1).strip())+    except Exception:+        pass+    return alerts+++def _extract_export_path(eagle_cmd: str) -> str | None:+    """Extract the output file path from an EAGLE EXPORT command.++    EAGLE EXPORT commands use single-quoted paths:+      EXPORT NETLIST 'C:/tmp/netlist.txt'+      EXPORT IMAGE 'C:/tmp/board.png' 300+      EXPORT PARTLIST 'C:/tmp/parts.txt'++    Returns the unquoted path, or None if not found.+    """+    # Match single-quoted path+    m = re.search(r"'([^']+)'", eagle_cmd)+    if m:+        return m.group(1)+    # Fallback: look for unquoted path-like tokens (with / or \ and an extension)+    parts = eagle_cmd.strip().split()+    for part in parts[2:]:  # Skip "EXPORT" and subcommand+        cleaned = part.strip("'\"")+        if ("/" in cleaned or "\\" in cleaned) and "." in cleaned:+            return cleaned+    return None+++def _get_workspace_info(app: adsk.core.Application) -> dict:+    """Get current workspace info and whether Electronics Electron editor is active."""+    try:+        active_ws = app.executeTextCommand("DebugCommands.ActiveWorkspace")+    except Exception:+        active_ws = "unknown"++    is_electron = False+    try:+        app.executeTextCommand("Electron.run DISPLAY")+        is_electron = True+    except Exception:+        pass++    # Get document info+    doc_info = None+    try:+        doc = app.activeDocument+        if doc:+            doc_info = {"name": doc.name, "type": str(doc.documentType)}+    except Exception:+        pass++    # Get product type+    product_type = None+    try:+        product = app.activeProduct+        if product:+            product_type = product.productType+    except Exception:+        pass++    info = {+        "activeWorkspace": active_ws.strip() if active_ws else "unknown",+        "isElectronics": is_electron,+    }+    if doc_info:+        info["document"] = doc_info+    if product_type:+        info["productType"] = product_type+    return info+++def _get_recent_operations(app: adsk.core.Application, count: int = 5) -> list:+    """Get recent Fusion operations log via Diagnostics.RecentOperations."""+    try:+        result = app.executeTextCommand(f"Diagnostics.RecentOperations {count}")+        if result:+            lines = [l.strip() for l in result.strip().split("\r\n") if l.strip()]+            # Filter to just command begin/end, skip DLL loads+            return [l for l in lines if l.startswith("Command ")]+        return []+    except Exception:+        return []+++def _query_post_command_state(app: adsk.core.Application, eagle_cmd: str, ops_before: list) -> dict:+    """Query Fusion state after an Electron.run command to return meaningful feedback.++    Uses Diagnostics.RecentOperations to diff what actually happened, plus+    workspace/document state for context.+    """+    import time+    time.sleep(0.3)  # Brief pause for command to take effect++    state = {}++    # Always include workspace info+    try:+        active_ws = app.executeTextCommand("DebugCommands.ActiveWorkspace")+        state["activeWorkspace"] = active_ws.strip() if active_ws else "unknown"+    except Exception:+        state["activeWorkspace"] = "unknown"++    # Active document+    try:+        doc = app.activeDocument+        if doc:+            state["activeDocument"] = doc.name+    except Exception:+        pass++    # Diff operations log — what commands fired as a result?+    ops_after = _get_recent_operations(app, 10)+    if ops_before and ops_after:+        # Find new operations that weren't in the before snapshot+        new_ops = []+        for op in ops_after:+            if op not in ops_before:+                new_ops.append(op)+        if new_ops:+            state["fusionOperations"] = new_ops[:5]  # Cap at 5 to keep response size sane++    # Parse command to provide targeted feedback+    cmd_parts = eagle_cmd.strip().split(None, 1)+    cmd_verb = cmd_parts[0].upper() if cmd_parts else ""+    cmd_upper = eagle_cmd.strip().upper()++    # Command-specific hints and extra queries+    if cmd_verb == "DISPLAY":+        state["commandType"] = "layer_visibility"+        state["hint"] = "DISPLAY command executed. Use fusion_take_screenshot to verify layer changes visually."++    elif cmd_verb == "WINDOW":+        state["commandType"] = "view_control"+        state["hint"] = "Zoomed to fit all content in view." if "FIT" in cmd_upper else "View position/zoom changed."++    elif cmd_verb == "EDIT":+        target = cmd_parts[1] if len(cmd_parts) > 1 else ""+        state["commandType"] = "edit"+        ext_map = {".sym": "symbol", ".pac": "package", ".dev": "device"}+        for ext, editor in ext_map.items():+            if target.endswith(ext):+                state["hint"] = f"Opened {editor} editor for: {target}"+                state["editorType"] = editor+                break+        else:+            state["hint"] = f"Opened editor for: {target}"++    elif cmd_verb == "RATSNEST":+        state["commandType"] = "ratsnest"+        state["hint"] = "Ratsnest (airwires) recalculated."++    elif cmd_verb == "BOARD":+        state["commandType"] = "view_switch"+        state["hint"] = "Requested switch to board layout. Verify with a screenshot."++    elif cmd_verb == "SET":+        state["commandType"] = "setting"+        state["hint"] = f"Setting changed: {eagle_cmd.strip()}"++    elif cmd_verb == "SCRIPT":+        state["commandType"] = "script"+        state["hint"] = f"Script executed: {cmd_parts[1] if len(cmd_parts) > 1 else '(unknown)'}"++    elif cmd_verb == "USE":+        state["commandType"] = "library_load"+        state["hint"] = f"Library load requested: {cmd_parts[1] if len(cmd_parts) > 1 else '(unknown)'}"++    elif cmd_verb in ("NAME", "VALUE", "SMASH", "MOVE", "ROTATE", "DELETE", "COPY", "GROUP",+                       "ROUTE", "RIPUP", "WIRE", "CIRCLE", "RECT", "POLYGON", "TEXT", "ARC",+                       "PAD", "SMD", "VIA", "HOLE", "PIN", "LABEL", "NET", "BUS", "JUNCTION"):+        state["commandType"] = "design_edit"+        state["hint"] = f"Design edit command executed: {cmd_verb}"++    elif cmd_verb == "EXPORT":+        state["commandType"] = "export"+        # Try to verify the export actually produced a file+        # Parse output path from command: EXPORT <TYPE> <path> [options]+        export_parts = eagle_cmd.strip().split()+        export_path = None+        if len(export_parts) >= 3:+            # The path is typically the 3rd token (after EXPORT <TYPE>)+            candidate = export_parts[2]+            # Handle quoted paths+            if candidate.startswith(("'", '"')):+                quote = candidate[0]+                rest = eagle_cmd.strip().split(quote)+                if len(rest) >= 3:+                    export_path = rest[1]+            else:+                export_path = candidate++        if export_path:+            import os+            if os.path.exists(export_path):+                fsize = os.path.getsize(export_path)+                state["hint"] = f"Export succeeded: {export_path} ({fsize} bytes)"+                state["exportedFile"] = export_path+                state["exportedFileSize"] = fsize+            else:+                state["hint"] = (+                    f"Export command ran but output file NOT found at: {export_path}. "+                    "The EAGLE command may have failed silently — check Fusion's error toast or operations log."+                )+                state["exportFailed"] = True+                state["expectedPath"] = export_path+        else:+            state["hint"] = f"Export command executed: {eagle_cmd.strip()}"++    else:+        state["commandType"] = "generic"+        state["hint"] = f"Command executed: {eagle_cmd.strip()}. Use fusion_take_screenshot to verify the result visually."++    # If no Fusion operations fired, the command likely failed silently.+    # EAGLE's Electron.run never returns errors — failures only show as+    # toast dialogs on the user's screen that are invisible to the API.+    # We check Fusion's error log for alert toasts (see handle_electron_run),+    # but log writes are async so errors may appear after our check window.+    if "fusionOperations" not in state or not state["fusionOperations"]:+        state["possibleFailure"] = True+        state["hint"] = (+            f"WARNING: No Fusion operations detected after '{cmd_verb}'. "+            f"The command likely failed silently. Check the 'alertErrors' field "+            f"in this response — if populated, it contains the actual Fusion error "+            f"message captured from the log. If 'alertErrors' is empty, the error "+            f"may not have been logged yet; take a screenshot with "+            f"fusion_take_screenshot to see the error toast in Fusion's UI. "+            f"Original hint: {state.get('hint', '')}"+        )++    return state+++def handle_electron_run(app: adsk.core.Application, args: dict) -> dict:+    """Execute an EAGLE command in the Electronics workspace via Electron.run.++    Requires an active Electronics editor (schematic, board, or library).+    Returns workspace state + Fusion operations log diff after execution.++    Args:+        args: Dict with:+            - command: The EAGLE command to execute (required).+              Examples: "EDIT resistor.sym", "USE mylib.lbr", "WINDOW FIT"+    """+    eagle_cmd = args.get("command", "")+    if not eagle_cmd:+        return {"success": False, "error": "No command specified. Provide an EAGLE command string."}++    # Check we're in Electronics before executing+    ws_info = _get_workspace_info(app)+    if not ws_info["isElectronics"]:+        return {+            "success": False,+            "error": f"Not in Electronics editor (current: {ws_info['activeWorkspace']}). "+                     "Open a schematic or board in Fusion 360's Electronics workspace first.",+            "_hint": "Call fusion_open_schematic {\"filePath\":\"...\"}, fusion_open_board {\"filePath\":\"...\"}, or fusion_open_lbr {\"filePath\":\"...\"} to enter the Electronics editor, then retry.",+            "data": {+                **ws_info,+                "hint": "Use fusion_open_schematic, fusion_open_board, or fusion_open_lbr to open an electronics file first.",+            },+        }++    # Parse the first word as the command verb for validation and routing.+    cmd_verb = eagle_cmd.strip().split()[0].upper() if eagle_cmd.strip() else ""++    # Block commands that don't work in Fusion's Electronics workspace or that+    # pop up error dialogs on the user's screen with no useful result.+    BLOCKED_COMMANDS = {+        "SCHEMATIC": "Use fusion_show_2d_board or fusion_electron_run '{\"command\": \"BOARD\"}' to switch between schematic/board views. "+                     "The SCHEMATIC command doesn't exist in Fusion's EAGLE integration.",+        "ADD": "Opens an interactive component picker dialog that blocks automation. "+               "Place components through the Fusion UI instead.",+        "SHOW": "Opens interactive highlight mode that blocks automation. "+                "Use fusion_board_info to query component/net data instead.",+        "CHANGE": "Opens interactive change mode that blocks automation.",+        "MOVE": "Opens interactive move mode — requires clicking to place. "+                "Not suitable for CLI automation. Use the Fusion API to move components programmatically.",+    }++    # WRITE always opens a blocking "Version Description" dialog on cloud docs,+    # even when a path argument is provided. Tested 2026-04-10 — WRITE <path>+    # still triggers the dialog. Block unconditionally.+    if cmd_verb == "WRITE":+        return {+            "success": False,+            "error": "Command 'WRITE' is blocked — it opens a blocking 'Version Description' save dialog "+                     "on cloud documents, even when a path argument is provided (tested 2026-04-10). "+                     "Use fusion_export_source for .fsch/.fbrd export, or fusion_export_eagle_source for .sch/.brd.",+            "_hint": "For Fusion-format source: fusion_export_source {\"outputPath\":\"C:/out/file.fbrd\"}. "+                     "For EAGLE-format source: fusion_export_eagle_source {\"outputPath\":\"C:/out/file.brd\"}.",+            "data": {+                "command": eagle_cmd,+                "blockedVerb": "WRITE",+                "activeWorkspace": ws_info["activeWorkspace"],+            },+        }++    if cmd_verb in BLOCKED_COMMANDS:+        return {+            "success": False,+            "error": f"Command '{cmd_verb}' is blocked for automation: {BLOCKED_COMMANDS[cmd_verb]}",+            "_hint": f"'{cmd_verb}' opens an interactive dialog. Use fusion_board_info / fusion_save_to_cloud / the Fusion API alternatives instead of this EAGLE command.",+            "data": {+                "command": eagle_cmd,+                "blockedVerb": cmd_verb,+                "hint": BLOCKED_COMMANDS[cmd_verb],+                "activeWorkspace": ws_info["activeWorkspace"],+            },+        }++    # Auto-suppress overwrite/confirmation dialogs for EXPORT commands.+    # Without this, EAGLE shows a Qt "Overwrite?" dialog that blocks the+    # add-in thread and is invisible to the CLI/AI — freezing everything.+    export_target_path = None+    if cmd_verb == "EXPORT":+        try:+            app.executeTextCommand("Electron.run SET CONFIRM YES")+        except Exception:+            pass  # Best effort — don't block if SET fails++        # Extract the output file path from the EXPORT command.+        # EAGLE EXPORT syntax: EXPORT <type> '<path>' [options]+        # Paths are typically single-quoted: EXPORT NETLIST '/path/to/file.txt'+        export_target_path = _extract_export_path(eagle_cmd)+        if export_target_path and os.path.exists(export_target_path):+            try:+                os.remove(export_target_path)+            except PermissionError:+                return {+                    "success": False,+                    "error": f"Cannot overwrite '{export_target_path}' — file is locked by another process.",+                    "_hint": "Choose a different outputPath (e.g., append a timestamp) and retry the EXPORT command.",+                    "data": {+                        "command": eagle_cmd,+                        "filePath": export_target_path,+                        "hint": "The target file exists and is locked. Close any program using it, "+                                "or choose a different output path.",+                        "nextSteps": [+                            f"Delete or rename '{export_target_path}' manually",+                            "Or use a different output path in the EXPORT command",+                        ],+                    },+                }+            except Exception as e:+                return {+                    "success": False,+                    "error": f"Cannot remove existing file '{export_target_path}': {e}",+                    "data": {+                        "command": eagle_cmd,+                        "filePath": export_target_path,+                        "hint": "Pre-delete failed. Use a different output path to avoid the overwrite dialog.",+                    },+                }++    # Snapshot operations log and Fusion error log BEFORE execution+    ops_before = _get_recent_operations(app, 10)+    log_path = _get_fusion_log_path()+    log_line_before = _get_log_line_count(log_path) if log_path else 0++    try:+        raw_result = app.executeTextCommand(f"Electron.run {eagle_cmd}")+    except Exception as e:+        return {+            "success": False,+            "error": f"Electron.run failed: {e}",+            "_hint": "Check the active workspace with fusion_execute_text_command {\"command\": \"DebugCommands.ActiveWorkspace\"} — EAGLE commands need the right editor (schematic vs board vs library). Call fusion_open_schematic / fusion_open_board / fusion_open_lbr to switch.",+            "data": {+                "command": eagle_cmd,+                "hint": "The command may be invalid or require a specific editor context (schematic vs board vs library).",+            },+        }++    # Query state after execution — includes ops log diff+    post_state = _query_post_command_state(app, eagle_cmd, ops_before)++    # Check Fusion's error log for alert messages that appeared after the command.+    # These are the toast errors shown in the lower-right of Fusion's UI that+    # Electron.run silently swallows — the only way to detect them is via the log.+    # Fusion writes to the log asynchronously, so we poll with increasing delays.+    alert_errors = []+    if log_path:+        import time+        for _attempt in range(4):+            time.sleep(0.3 if _attempt == 0 else 0.5)+            alert_errors = _check_log_for_alerts(log_path, log_line_before)+            if alert_errors:+                break++    # Detect export failures (command ran but output file not created)+    succeeded = True+    if post_state.get("exportFailed"):+        succeeded = False++    # If Fusion logged alert errors, the command failed+    if alert_errors:+        succeeded = False+        post_state["alertErrors"] = alert_errors+        post_state["hint"] = (+            f"EAGLE error: {alert_errors[0]}. "+            f"Original hint: {post_state.get('hint', '')}"+        )++    # For EXPORT commands, verify the output file exists and report size+    export_data = {}+    if cmd_verb == "EXPORT" and export_target_path:+        import time+        time.sleep(0.5)  # Give EAGLE a moment to flush to disk+        if os.path.exists(export_target_path):+            fsize = os.path.getsize(export_target_path)+            export_data = {+                "exportedFile": export_target_path,+                "fileSizeBytes": fsize,+                "fileSizeKB": fsize // 1024,+            }+            succeeded = True  # Override exportFailed if file actually exists+        else:+            succeeded = False+            export_data = {+                "exportedFile": export_target_path,+                "exportFailed": True,+                "hint": f"EXPORT command ran but file was not created at '{export_target_path}'. "+                        "This EXPORT subcommand may not be supported in the current editor context.",+            }++    result = {+        "success": succeeded,+        "error": alert_errors[0] if alert_errors else "",+        "output": post_state.get("hint", f"Executed: {eagle_cmd}"),+        "data": {+            "command": eagle_cmd,+            "rawResult": raw_result if raw_result else "",+            "alertErrors": alert_errors,+            **post_state,+            **export_data,+        },+    }++    # If we suspect failure but didn't catch a log error, hint the AI+    # that errors from Electron.run are async — the real error may appear+    # in the next command's alertErrors or in a screenshot.+    if post_state.get("possibleFailure") and not alert_errors:+        result["data"]["asyncErrorHint"] = (+            "Electron.run is fire-and-forget — errors only appear as toast "+            "dialogs in Fusion's UI. The error log was checked but nothing "+            "appeared yet. Run fusion_take_screenshot to see the current "+            "Fusion state and check for error toasts."+        )++    return result+++def handle_open_electronics(app: adsk.core.Application, args: dict) -> dict:+    """Check Electronics workspace status and optionally open a file.++    PCB/ELECTRONICS NAV RULE: a board is NOT a standalone file - the schematic, 2D board and 3D board are VIEWS inside ONE electronics DESIGN. Open the DESIGN document first (fusion_open_cloud_file or fusion_open_by_urn), THEN switch to its schematic and its 2D board (fusion_show_2d_board) and 3D board (fusion_show_3d_board). A Select-Electronics-Design-File picker IS that design list of its schematic + board. An EMPTY 2D board usually means you opened a derivative or the wrong file, or it is out of sync - reopen the parent electronics DESIGN and switch to its board view; do NOT open a .brd or .sch as a standalone file.++    Args:+        args: Dict with:+            - type: "status" to just check (default). Other values reserved+                   for future use (workspace switching handled by bridge server).+            - filePath: Optional path to a .sch, .brd, or .lbr file to open+                       (only works if already in Electronics editor).+    """+    file_path = args.get("filePath", "")+    ws_info = _get_workspace_info(app)++    # If already in electronics, handle file opening or return status+    if ws_info["isElectronics"]:+        if file_path:+            try:+                result = app.executeTextCommand(f"Electron.run EDIT '{file_path}'")+                return {+                    "success": True,+                    "output": f"Opened {file_path} in Electronics workspace.",+                    "data": {"result": result if result else "", **ws_info},+                }+            except Exception as e:+                return {+                    "success": False,+                    "error": f"Failed to open {file_path}: {e}",+                    "_hint": "Verify the file exists on the Windows host, then try fusion_open_schematic or fusion_open_board with the correct filePath.",+                }+        return {+            "success": True,+            "output": "Electronics editor is active. Electron.run commands will work.",+            "data": ws_info,+        }++    # Not in Electronics — report status+    return {+        "success": True,+        "output": f"Not in Electronics editor (current workspace: {ws_info['activeWorkspace']}).",+        "data": ws_info,+    }+++def handle_export_source(app: adsk.core.Application, args: dict) -> dict:+    """Export the active electronics document as .fsch, .fbrd, or .flbr source file.++    Uses Fusion's Document.CopyToDesktop text command, which exports the+    currently active document in its native format based on the file extension.++    PREREQUISITES — the caller MUST set up the correct view before calling:++    To export .fbrd (board):+      1. Open the .fprj:  fusion_open_cloud_file {"projectName":"Main", "fileName":"MyDesign", "fileExtension":"fprj", ...}+      2. Enter board view: fusion_show_2d_board+      3. Export:           fusion_export_source {"outputPath": "C:/out/MyDesign.fbrd"}++    To export .fsch (schematic):+      4. Switch to schematic: fusion_electron_run {"command": "EDIT .s1"}+      5. Export:              fusion_export_source {"outputPath": "C:/out/MyDesign.fsch"}++    To export .flbr (library):+      1. Open the .lbr:   fusion_open_lbr {"filePath": "C:/path/to/lib.lbr"}+      2. Export:           fusion_export_source {"outputPath": "C:/out/MyLib.flbr"}++    IMPORTANT GOTCHAS:+    - You MUST open the .fprj file first, NOT .fbrd/.fsch directly+    - You MUST call show_2d_board before exporting .fbrd (the 3D board view won't work)+    - To switch between board and schematic: use EDIT .s1 (schematic) or EDIT .brd (board)+    - The active workspace MUST be "Board Layout" for .fbrd or "Schematic Editor" for .fsch+    - If the wrong workspace is active, the file will not be created+    - After opening cloud file, wait for the document to fully load before exporting+    - Always screenshot after open to check for blocking dialogs before exporting++    Args:+        args: Dict with:+            - outputPath: Required. Full path including extension (.fsch, .fbrd, or .flbr).+              The extension determines the export format.+    """+    import os++    output_path = args.get("outputPath", "").strip()+    if not output_path:+        return {+            "success": False,+            "error": "Missing required arg: outputPath",+            "_hint": "Provide outputPath with extension .fsch, .fbrd, or .flbr. "+                     "For plain EAGLE format (.sch/.brd), use fusion_export_eagle_source instead.",+        }++    # Validate extension+    ext = os.path.splitext(output_path)[1].lower()+    valid_exts = {".fsch", ".fbrd", ".flbr"}+    if ext not in valid_exts:+        return {+            "success": False,+            "error": f"Invalid extension '{ext}'. Must be one of: {', '.join(sorted(valid_exts))}",+            "_hint": "Use .fsch for schematic source, .fbrd for board source, .flbr for library source. "+                     "For plain EAGLE format (.sch/.brd), use fusion_export_eagle_source instead.",+        }++    # Ensure output directory exists+    out_dir = os.path.dirname(output_path)+    if out_dir:+        os.makedirs(out_dir, exist_ok=True)++    # Normalize path for Fusion (use forward slashes)+    fusion_path = output_path.replace("\\", "/")++    try:+        result = app.executeTextCommand(f"Document.CopyToDesktop {fusion_path}")+    except Exception as e:+        return {+            "success": False,+            "error": f"Document.CopyToDesktop failed: {e}",+            "_hint": "Ensure the correct workspace is active: Board Layout for .fbrd, Schematic Editor for .fsch, Electronics Library for .flbr. Call fusion_show_2d_board or fusion_electron_run {\"command\":\"EDIT .s1\"} to switch.",+        }++    # Verify file was created+    # Fusion may use the exact path or normalize it+    check_path = output_path.replace("/", "\\")+    if not os.path.exists(check_path) and not os.path.exists(output_path):+        return {+            "success": False,+            "error": f"Command ran but file not found at {output_path}. "+                     "Make sure the correct editor is active (Board Layout for .fbrd, "+                     "Schematic Editor for .fsch).",+            "_hint": "Call fusion_show_2d_board (for .fbrd) or fusion_electron_run {\"command\":\"EDIT .s1\"} (for .fsch) to activate the right workspace, then retry.",+            "data": {"commandResult": result.strip() if result else ""},+        }++    actual_path = check_path if os.path.exists(check_path) else output_path+    size_bytes = os.path.getsize(actual_path)++    # Get active document context+    doc_name = ""+    workspace = ""+    try:+        doc = app.activeDocument+        if doc:+            doc_name = doc.name+        workspace = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+    except Exception:+        pass++    return {+        "success": True,+        "output": f"Exported {ext} source ({size_bytes:,} bytes) to {output_path}",+        "data": {+            "savedTo": output_path.replace("\\", "/"),+            "sizeBytes": size_bytes,+            "format": ext.lstrip("."),+            "activeDocument": doc_name,+            "activeWorkspace": workspace,+        },+    }+++def handle_export_eagle_source(app: adsk.core.Application, args: dict) -> dict:+    """Export the active electronics document as plain EAGLE .sch or .brd XML.++    Fusion's .fsch/.fbrd files are ZIP containers with a real EAGLE .sch/.brd+    XML file inside at `electron.BlobParts/ExtFile.*.{sch,brd}`. This command:+      1. Exports the .fsch/.fbrd via Document.CopyToDesktop (same as fusion_export_source)+      2. Extracts the inner EAGLE XML from the ZIP+      3. Writes it to outputPath as a plain EAGLE file+      4. Cleans up the intermediate .fsch/.fbrd++    The resulting file is valid EAGLE XML (`<?xml ...><eagle version="9.7.0">...`)+    that can be opened by standalone EAGLE, KiCad (via import), or parsed by any+    XML tool.++    PREREQUISITES — same as fusion_export_source:+      Board (.brd):  must be in "Board Layout" / "PCB Editor" workspace+      Schematic (.sch): must be in "Schematic Editor" workspace++    Args:+        args: Dict with:+            - outputPath: Required. Full path ending in .sch or .brd.+    """+    import tempfile+    import zipfile++    output_path = args.get("outputPath", "").strip()+    if not output_path:+        return {"success": False, "error": "Missing required arg: outputPath"}++    ext = os.path.splitext(output_path)[1].lower()+    valid_exts = {".sch": ".fsch", ".brd": ".fbrd"}+    if ext not in valid_exts:+        return {+            "success": False,+            "error": f"Invalid extension '{ext}'. Must be .sch or .brd.",+            "_hint": "For Fusion-format source (.fsch/.fbrd/.flbr), use fusion_export_source instead.",+        }++    fusion_ext = valid_exts[ext]  # .sch -> .fsch, .brd -> .fbrd++    # Export to a temp .fsch/.fbrd first+    tmp_dir = tempfile.mkdtemp(prefix="adom-eagle-")+    tmp_fusion_path = os.path.join(tmp_dir, f"temp{fusion_ext}")+    fusion_path = tmp_fusion_path.replace("\\", "/")++    try:+        result = app.executeTextCommand(f"Document.CopyToDesktop {fusion_path}")+    except Exception as e:+        return {+            "success": False,+            "error": f"Document.CopyToDesktop failed: {e}",+            "_hint": "Ensure the correct workspace is active: PCB Editor / Board Layout for .brd, "+                     "Schematic Editor for .sch. Use fusion_show_2d_board or "+                     "fusion_electron_run {\"command\":\"EDIT .s1\"} to switch.",+        }++    # Check if the file was created+    check_path = tmp_fusion_path.replace("/", "\\")+    actual_tmp = None+    for p in [check_path, tmp_fusion_path]:+        if os.path.exists(p):+            actual_tmp = p+            break++    if not actual_tmp:+        return {+            "success": False,+            "error": f"Document.CopyToDesktop ran but intermediate {fusion_ext} file not found.",+            "_hint": "Ensure the correct workspace is active: PCB Editor / Board Layout for .brd, "+                     "Schematic Editor for .sch.",+        }++    # Extract the EAGLE XML from the ZIP container+    eagle_data = None+    inner_name = None+    try:+        with zipfile.ZipFile(actual_tmp, "r") as zf:+            for name in zf.namelist():+                if name.endswith(ext):  # Find the .sch or .brd inside+                    eagle_data = zf.read(name)+                    inner_name = name+                    break+    except Exception as e:+        # Clean up temp+        try:+            os.remove(actual_tmp)+            os.rmdir(tmp_dir)+        except Exception:+            pass+        return {+            "success": False,+            "error": f"Failed to read {fusion_ext} ZIP container: {e}",+        }++    # Clean up temp file+    try:+        os.remove(actual_tmp)+        os.rmdir(tmp_dir)+    except Exception:+        pass++    if not eagle_data:+        return {+            "success": False,+            "error": f"No {ext} file found inside {fusion_ext} ZIP container.",+            "_hint": "The Fusion container format may have changed. Use fusion_export_source "+                     "to get the raw .fsch/.fbrd and inspect with a ZIP tool.",+        }++    # Verify it looks like EAGLE XML+    header = eagle_data[:100].decode("utf-8", errors="replace")+    if "<eagle" not in header and "<?xml" not in header:+        return {+            "success": False,+            "error": f"Extracted file does not appear to be EAGLE XML. "+                     f"First 100 bytes: {header!r}",+        }++    # Write to output path+    out_dir = os.path.dirname(output_path)+    if out_dir:+        os.makedirs(out_dir, exist_ok=True)++    with open(output_path, "wb") as f:+        f.write(eagle_data)++    size_bytes = len(eagle_data)++    # Get context+    doc_name = ""+    workspace = ""+    try:+        doc = app.activeDocument+        if doc:+            doc_name = doc.name+        workspace = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+    except Exception:+        pass++    return {+        "success": True,+        "output": f"Exported EAGLE {ext} ({size_bytes:,} bytes) to {output_path}",+        "data": {+            "savedTo": output_path.replace("\\", "/"),+            "sizeBytes": size_bytes,+            "format": ext.lstrip("."),+            "innerZipEntry": inner_name,+            "activeDocument": doc_name,+            "activeWorkspace": workspace,+        },+        "_hint": "This is a plain EAGLE XML file — parseable by standalone EAGLE, "+                 "KiCad import, or any XML tool. For Fusion-format source, use "+                 "fusion_export_source instead.",+    }+++def handle_execute_text_command(app: adsk.core.Application, args: dict) -> dict:+    """Execute any Fusion 360 text command directly.++    This is a lower-level command that runs `app.executeTextCommand()` without+    any wrapper. Useful for workspace info, debugging, or non-Electron commands.++    Unlike Electron.run, many text commands DO return meaningful results+    (e.g., DebugCommands.ActiveWorkspace returns the workspace name).++    Args:+        args: Dict with:+            - command: The full text command to execute (required).+    """+    text_cmd = args.get("command", "")+    if not text_cmd:+        return {"success": False, "error": "No command specified."}++    try:+        result = app.executeTextCommand(text_cmd)++        data = {"command": text_cmd, "result": result.strip() if result else ""}++        # Add workspace context for common debug queries+        if not text_cmd.startswith("DebugCommands.ActiveWorkspace"):+            try:+                ws = app.executeTextCommand("DebugCommands.ActiveWorkspace")+                data["activeWorkspace"] = ws.strip() if ws else "unknown"+            except Exception:+                pass++        try:+            doc = app.activeDocument+            if doc:+                data["activeDocument"] = doc.name+        except Exception:+            pass++        return {+            "success": True,+            "output": result.strip() if result else f"Executed: {text_cmd} (no output)",+            "data": data,+        }+    except Exception as e:+        return {+            "success": False,+            "error": f"Text command failed: {e}",+            "_hint": "Call fusion_list_text_commands to discover valid commands, or verify the active workspace supports this command.",+        }+++def handle_list_text_commands(app: adsk.core.Application, args: dict) -> dict:+    """List available Fusion 360 text commands matching a filter.++    Args:+        args: Dict with:+            - filter: Optional filter string (default: "Electron").+    """+    filter_str = args.get("filter", "Electron")++    try:+        result = app.executeTextCommand("TextCommands.List")+        if result:+            lines = result.split("\n")+            matching = [l for l in lines if filter_str.lower() in l.lower()]+            return {+                "success": True,+                "output": f"Found {len(matching)} commands matching '{filter_str}'",+                "data": {+                    "commands": matching[:50],+                    "total": len(matching),+                },+            }+        return {+            "success": True,+            "output": "TextCommands.List returned no output",+            "data": {"commands": []},+        }+    except Exception as e:+        return {+            "success": False,+            "error": f"TextCommands.List failed: {e}",+            "_hint": "Ensure an Electronics workspace is active — call fusion_open_schematic, fusion_open_board, or fusion_open_lbr first, then retry.",+        }+++def handle_board_info(app: adsk.core.Application, args: dict) -> dict:+    """Get structured board data from the current PCB layout.++    Returns XML with copper traces, pads, component placements (name, x, y,+    rotation), net names, layer setup, board thickness, DRC violations, and+    library packages used. Only works when a .brd board is open in PCB Editor.++    This is much richer than a screenshot — the AI can read exact coordinates,+    net connectivity, and component positions.+    """+    # Electron.boardInfo requires an output file path+    board_info_path = os.path.join(tempfile.gettempdir(), "adom_board_info.xml")++    try:+        app.executeTextCommand(f"Electron.boardInfo {board_info_path}")+    except Exception as e:+        err_msg = str(e)+        if "not PCB2d document" in err_msg.lower() or "not pcb" in err_msg.lower():+            ws = "unknown"+            try:+                ws = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+            except Exception:+                pass+            return {+                "success": False,+                "error": f"No board open (current workspace: {ws}). Open a .brd file first with fusion_open_board.",+                "_hint": "Call fusion_open_board {\"filePath\":\"...\"} or fusion_show_2d_board to enter Board Layout, then retry.",+                "data": {"activeWorkspace": ws},+            }+        return {+            "success": False,+            "error": f"boardInfo failed: {e}",+            "_hint": "Ensure a .brd file is open in Board Layout — call fusion_show_2d_board first, then retry.",+        }++    # Read the output file (Fusion writes UTF-16 LE BOM)+    result = None+    for enc in ("utf-16", "utf-8-sig", "utf-8"):+        try:+            with open(board_info_path, "r", encoding=enc) as f:+                result = f.read()+            break+        except (UnicodeDecodeError, UnicodeError):+            continue+    if result is None:+        try:+            with open(board_info_path, "rb") as f:+                raw = f.read()+            return {"success": False, "error": f"Failed to decode boardInfo (first bytes: {raw[:20].hex()})"}+        except Exception as e:+            return {"success": False, "error": f"Failed to read boardInfo output: {e}"}++    if not result:+        return {"success": False, "error": "boardInfo returned no data. Is a .brd board open?"}++    # Parse the XML to extract a summary for the AI+    import xml.etree.ElementTree as ET+    summary = {}+    try:+        root = ET.fromstring(result)+        board = root.find("g")+        if board is not None:+            summary["name"] = board.get("name", "")+            summary["unit"] = board.get("unit", "mm")+            summary["boardThickness"] = board.get("boardThickness", "")+            summary["layerSetup"] = board.get("layersetup", "")++        # Extract component placements from <libraries>+        components = []+        for lib_group in root.iter("g"):+            lib = lib_group.get("library")+            pkg = lib_group.get("package")+            if lib and pkg:+                for comp in lib_group.findall("g"):+                    name = comp.get("name")+                    if name:+                        components.append({+                            "name": name,+                            "library": lib,+                            "package": pkg,+                            "x": comp.get("x"),+                            "y": comp.get("y"),+                            "rotation": comp.get("rot", "R0"),+                            "locked": comp.get("LOCKED", "false") == "true",+                        })+        summary["components"] = components+        summary["componentCount"] = len(components)++        # Extract net names from copper traces+        nets = set()+        for copper in root.iter("copper"):+            net_name = copper.get("name", "")+            if net_name:+                nets.add(net_name)+        summary["nets"] = sorted(nets)+        summary["netCount"] = len(nets)++        # Extract DRC issues+        drc = root.find(".//drc")+        if drc is not None:+            overlaps = []+            for overlap in drc.findall(".//overlap"):+                for signal in overlap.findall("signal"):+                    overlaps.append(signal.get("name", ""))+            if overlaps:+                summary["drcOverlaps"] = overlaps++    except ET.ParseError:+        # If XML parsing fails, just return the raw result+        pass++    return {+        "success": True,+        "output": f"Board info: {summary.get('name', 'unknown')}, "+                  f"{summary.get('componentCount', 0)} components, "+                  f"{summary.get('netCount', 0)} nets",+        "data": {+            "summary": summary,+            "rawXml": result,  # Full XML for detailed analysis if needed+        },+    }
addin/AdomBridge/commands/export.pyadded+693
@@ -0,0 +1,693 @@+"""Export commands — STEP, STL, 3MF, F3D, FBX.++All 3D export commands require an active Fusion Design (3D PCB view or a CAD+design document). Switch to 3D PCB view with fusion_show_3d_board before+exporting from an electronics project.+"""++import adsk.core+import adsk.fusion+import os+import time+from pathlib import Path+++# Shared hint constants — reused across every export handler.+_HINT_NO_OUTPUT_PATH = (+    "Provide an outputPath arg like {\"outputPath\": \"C:\\\\path\\\\out.step\"}. "+    "The path must include the file extension matching the export format."+)+_HINT_FORMAT_UNAVAILABLE = (+    "This format isn't available in this Fusion build. "+    "Use fusion_export_step or fusion_export_stl as a fallback."+)+_HINT_EXPORT_FAILED = (+    "If this persists, call fusion_screenshot_fusion to check for a blocking dialog, "+    "then fusion_send_key with 'escape' or 'enter' to dismiss it. "+    "Wrong-workspace errors: call fusion_show_3d_board first."+)+_HINT_FILE_LOCKED = (+    "Close the file in any viewer (Blender, Windows Explorer preview, etc.), "+    "or call fusion_close_document first if it's open in Fusion, then retry."+)+++def _get_active_design(app: adsk.core.Application):+    """Get the active Fusion design, or None."""+    product = app.activeProduct+    if product and product.productType == "DesignProductType":+        return adsk.fusion.Design.cast(product)+    return None+++def _no_design_error():+    """Standard error when no active design is available."""+    return {+        "success": False,+        "error": "No active design open in Fusion 360.",+        "_hint": "If you're in PCB Editor (2D board), call fusion_show_3d_board to switch to 3D view. Otherwise call fusion_open_cloud_file to open a Design document, then retry.",+        "data": {+            "hint": "3D exports require a Design product. If you're in PCB Editor (2D board), "+                    "switch to 3D view first with fusion_show_3d_board.",+            "recoverySteps": [+                "Run fusion_show_3d_board to switch to 3D PCB view",+                "Or open a .f3d design document",+                "Then retry the export command",+            ],+        },+    }+++def _export_success(fmt: str, output_path: str, extra_msg: str = "") -> dict:+    """Standard success response for 3D exports."""+    size = os.path.getsize(output_path) if os.path.exists(output_path) else 0+    return {+        "success": True,+        "output": f"Exported {fmt} to {output_path}",+        "message": f"{fmt} file exported ({size // 1024} KB). "+                   f"{extra_msg}"+                   "Use pull_file to transfer to Docker.",+        "data": {+            "outputPath": output_path,+            "format": fmt.lower(),+            "fileSizeKB": size // 1024,+            "nextSteps": [+                "Use pull_file to transfer the file back to Docker",+                "Export other formats: fusion_export_step, fusion_export_stl, fusion_export_3mf, fusion_export_f3d, fusion_export_fbx",+            ],+        },+    }+++def handle_export_step(app: adsk.core.Application, args: dict) -> dict:+    """Export the active design as a STEP file (.step).++    Industry-standard CAD interchange format. Best for mechanical CAD+    interoperability (SolidWorks, CATIA, Creo, etc.).++    Args:+        outputPath: Full path for the output .step file (required).+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        return {"success": False, "error": "No outputPath specified", "_hint": _HINT_NO_OUTPUT_PATH}++    design = _get_active_design(app)+    if not design:+        return _no_design_error()++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    export_mgr = design.exportManager+    options = export_mgr.createSTEPExportOptions(output_path)+    result = export_mgr.execute(options)++    if result:+        return _export_success("STEP", output_path,+                               "Industry-standard CAD interchange — opens in any CAD tool. ")+    return {"success": False, "error": "STEP export failed", "_hint": _HINT_EXPORT_FAILED}+++def handle_export_stl(app: adsk.core.Application, args: dict) -> dict:+    """Export the active design as an STL file (.stl).++    Mesh-based format for 3D printing and visualization.++    Args:+        outputPath: Full path for the output .stl file (required).+        refinement: "low", "medium", or "high" (default: "medium").+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        return {"success": False, "error": "No outputPath specified", "_hint": _HINT_NO_OUTPUT_PATH}++    design = _get_active_design(app)+    if not design:+        return _no_design_error()++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    root = design.rootComponent+    export_mgr = design.exportManager+    options = export_mgr.createSTLExportOptions(root, output_path)++    refinement = args.get("refinement", "medium").lower()+    refinement_map = {+        "low": adsk.fusion.MeshRefinementSettings.MeshRefinementLow,+        "medium": adsk.fusion.MeshRefinementSettings.MeshRefinementMedium,+        "high": adsk.fusion.MeshRefinementSettings.MeshRefinementHigh,+    }+    options.meshRefinement = refinement_map.get(+        refinement, adsk.fusion.MeshRefinementSettings.MeshRefinementMedium+    )++    result = export_mgr.execute(options)++    if result:+        return _export_success("STL", output_path,+                               f"Mesh refinement: {refinement}. Good for 3D printing. ")+    return {"success": False, "error": "STL export failed", "_hint": _HINT_EXPORT_FAILED}+++def handle_export_3mf(app: adsk.core.Application, args: dict) -> dict:+    """Export the active design as a 3MF file (.3mf).++    Modern 3D printing format — supports color, materials, and multi-body.++    Args:+        outputPath: Full path for the output .3mf file (required).+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        return {"success": False, "error": "No outputPath specified", "_hint": _HINT_NO_OUTPUT_PATH}++    design = _get_active_design(app)+    if not design:+        return _no_design_error()++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    root = design.rootComponent+    export_mgr = design.exportManager+    options = export_mgr.createC3MFExportOptions(root, output_path)+    result = export_mgr.execute(options)++    if result:+        return _export_success("3MF", output_path,+                               "Modern 3D printing format with color/material support. ")+    return {"success": False, "error": "3MF export failed", "_hint": _HINT_EXPORT_FAILED}+++def handle_export_f3d(app: adsk.core.Application, args: dict) -> dict:+    """Export the active design as a Fusion 360 archive (.f3d).++    Native Fusion format — preserves all parametric features, sketches,+    timeline history, and component references. Best for archiving or+    sharing with other Fusion 360 users.++    Args:+        outputPath: Full path for the output .f3d file (required).+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        return {"success": False, "error": "No outputPath specified", "_hint": _HINT_NO_OUTPUT_PATH}++    design = _get_active_design(app)+    if not design:+        return _no_design_error()++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    export_mgr = design.exportManager+    options = export_mgr.createFusionArchiveExportOptions(output_path)+    result = export_mgr.execute(options)++    if result:+        return _export_success("F3D", output_path,+                               "Fusion 360 native archive — preserves all features and history. ")+    return {"success": False, "error": "F3D export failed", "_hint": _HINT_EXPORT_FAILED}+++def handle_export_usdz(app: adsk.core.Application, args: dict) -> dict:+    """Export the active design as a USDZ file (.usdz).++    Universal Scene Description (USD) — Pixar's scene-graph format adopted+    by Apple, NVIDIA, and Autodesk. Preserves:+    - Full component hierarchy (board, copper layers, soldermask, packages)+    - PBR materials and colors+    - Named nodes for toggling parts on/off in viewers++    Best format for digital twins, AR (Apple Quick Look), and GLB conversion+    via Blender. The component hierarchy maps directly to toggleable nodes+    in GLB viewers.++    Pipeline: Fusion → USDZ → Blender → GLB (or view USDZ directly on iOS)++    Args:+        outputPath: Full path for the output .usdz file (required).+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        return {"success": False, "error": "No outputPath specified", "_hint": _HINT_NO_OUTPUT_PATH}++    design = _get_active_design(app)+    if not design:+        return _no_design_error()++    # Ensure .usdz extension+    if not output_path.lower().endswith(('.usdz', '.usd', '.usda', '.usdc')):+        output_path = str(Path(output_path).with_suffix('.usdz'))++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    # Pre-delete to avoid overwrite dialogs+    if os.path.exists(output_path):+        try:+            os.remove(output_path)+        except PermissionError:+            return {+                "success": False,+                "error": f"Cannot overwrite {output_path} — file is locked.",+                "_hint": _HINT_FILE_LOCKED,+                "data": {+                    "hint": "Close the file in any viewer and retry.",+                    "outputPath": output_path,+                },+            }++    export_mgr = design.exportManager+    try:+        options = export_mgr.createUSDExportOptions(output_path)+    except AttributeError:+        return {+            "success": False,+            "error": "USDZ export not available in this Fusion 360 version.",+            "_hint": _HINT_FORMAT_UNAVAILABLE,+            "data": {+                "hint": "createUSDExportOptions requires a recent Fusion 360 build. "+                        "Export as STEP instead and convert via Blender.",+                "recoverySteps": [+                    "Export STEP: fusion_export_step (then convert in Blender)",+                    "Export OBJ: fusion_export_fbx (falls back to OBJ)",+                ],+            },+        }++    result = export_mgr.execute(options)++    if result and os.path.exists(output_path):+        size = os.path.getsize(output_path)++        # Get component hierarchy for the response+        components = []+        try:+            root = design.rootComponent+            for i in range(root.occurrences.count):+                occ = root.occurrences.item(i)+                components.append(occ.name)+        except Exception:+            pass++        return {+            "success": True,+            "output": f"Exported USDZ to {output_path}",+            "message": f"USDZ exported ({size // 1024} KB) with full component hierarchy. "+                       f"Contains {len(components)} top-level components that map to "+                       f"toggleable nodes in GLB viewers. "+                       f"Use pull_file to transfer to Docker.",+            "data": {+                "outputPath": output_path,+                "format": "usdz",+                "fileSizeKB": size // 1024,+                "components": components,+                "hint": "USDZ preserves PBR materials and scene hierarchy. "+                        "Each component (Board, copper layers, soldermask, Packages) "+                        "becomes a separate toggleable node in the GLB.",+                "nextSteps": [+                    "Use pull_file to transfer the USDZ to Docker",+                    "Convert to GLB: blender --background --python-expr "+                    "\"import bpy; bpy.ops.wm.read_factory_settings(use_empty=True); "+                    "bpy.ops.wm.usd_import(filepath='input.usdz'); "+                    "bpy.ops.export_scene.gltf(filepath='output.glb')\"",+                    "Or view directly on iOS/macOS — USDZ is Apple's native AR format",+                    "Or import into Unity/Unreal Engine for interactive 3D",+                ],+            },+        }++    return {"success": False, "error": "USDZ export failed", "_hint": _HINT_EXPORT_FAILED}+++def handle_export_fbx(app: adsk.core.Application, args: dict) -> dict:+    """Export the active design as an FBX file (.fbx).++    Autodesk FBX format — widely used for 3D interchange with Blender,+    Unity, Unreal Engine, and other DCC tools.++    NOTE: FBX export is not available in current Fusion 360 builds via the API.+    This command will fail clearly — use fusion_export_usdz or fusion_export_step+    instead. No silent fallbacks.++    Args:+        outputPath: Full path for the output .fbx file (required).+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        return {"success": False, "error": "No outputPath specified", "_hint": _HINT_NO_OUTPUT_PATH}++    design = _get_active_design(app)+    if not design:+        return _no_design_error()++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    # Pre-delete to avoid overwrite dialogs+    if os.path.exists(output_path):+        try:+            os.remove(output_path)+        except PermissionError:+            return {+                "success": False,+                "error": f"Cannot overwrite {output_path} — file is locked.",+                "_hint": _HINT_FILE_LOCKED,+                "data": {+                    "hint": "The file may be open in another application. Close it and retry.",+                    "outputPath": output_path,+                },+            }++    # Try FBX via exportManager API+    export_mgr = design.exportManager+    try:+        options = export_mgr.createFBXExportOptions(output_path)+        result = export_mgr.execute(options)+        if result and os.path.exists(output_path):+            return _export_success("FBX", output_path,+                                   "Convert to GLB via Blender: "+                                   "blender --background --python-expr "+                                   "\"import bpy; bpy.ops.import_scene.fbx(filepath='<fbx>'); "+                                   "bpy.ops.export_scene.gltf(filepath='<glb>')\" ")+    except (AttributeError, Exception):+        pass  # createFBXExportOptions doesn't exist in this Fusion build++    # FBX not available — fail clearly, no fallbacks+    return {+        "success": False,+        "error": "FBX export not available in this Fusion 360 build. "+                 "Use fusion_export_usdz or fusion_export_step instead.",+        "_hint": _HINT_FORMAT_UNAVAILABLE,+        "data": {+            "hint": "FBX is not supported via the Fusion API in current builds. "+                    "Use fusion_export_usdz (best for Blender/GLB pipeline, preserves "+                    "PBR materials and scene hierarchy) or fusion_export_step "+                    "(highest geometric fidelity).",+            "alternatives": ["fusion_export_usdz", "fusion_export_step", "fusion_export_stl"],+        },+    }+++def handle_export_dxf(app: adsk.core.Application, args: dict) -> dict:+    """Export the active design as a DXF file (.dxf).++    AutoCAD DXF (Drawing Exchange Format) — universal 2D/3D CAD interchange.+    Widely supported by all CAD tools, laser cutters, CNC routers, and+    PCB fabrication houses.++    Args:+        outputPath: Full path for the output .dxf file (required).+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        return {"success": False, "error": "No outputPath specified", "_hint": _HINT_NO_OUTPUT_PATH}++    design = _get_active_design(app)+    if not design:+        return _no_design_error()++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    if os.path.exists(output_path):+        try:+            os.remove(output_path)+        except PermissionError:+            return {+                "success": False,+                "error": f"Cannot overwrite {output_path} — file is locked.",+                "_hint": _HINT_FILE_LOCKED,+                "data": {"outputPath": output_path},+            }++    export_mgr = design.exportManager+    try:+        options = export_mgr.createDXFExportOptions(output_path)+        result = export_mgr.execute(options)+        if result and os.path.exists(output_path):+            return _export_success("DXF", output_path,+                                   "Universal CAD interchange — opens in AutoCAD, LibreCAD, etc. ")+    except (AttributeError, Exception):+        pass++    return {+        "success": False,+        "error": "DXF export failed or not available in this Fusion 360 build.",+        "_hint": _HINT_FORMAT_UNAVAILABLE,+        "data": {+            "hint": "Try fusion_export_step for CAD interchange instead.",+            "alternatives": ["fusion_export_step", "fusion_export_dwg"],+        },+    }+++def handle_export_dwg(app: adsk.core.Application, args: dict) -> dict:+    """Export the active design as a DWG file (.dwg).++    AutoCAD native format — the industry standard for 2D/3D technical+    drawings. Best for sharing with AutoCAD, BricsCAD, DraftSight users.++    Args:+        outputPath: Full path for the output .dwg file (required).+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        return {"success": False, "error": "No outputPath specified", "_hint": _HINT_NO_OUTPUT_PATH}++    design = _get_active_design(app)+    if not design:+        return _no_design_error()++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    if os.path.exists(output_path):+        try:+            os.remove(output_path)+        except PermissionError:+            return {+                "success": False,+                "error": f"Cannot overwrite {output_path} — file is locked.",+                "_hint": _HINT_FILE_LOCKED,+                "data": {"outputPath": output_path},+            }++    export_mgr = design.exportManager+    try:+        options = export_mgr.createDWGExportOptions(output_path)+        result = export_mgr.execute(options)+        if result and os.path.exists(output_path):+            return _export_success("DWG", output_path,+                                   "AutoCAD native format — opens in AutoCAD, BricsCAD, etc. ")+    except (AttributeError, Exception):+        pass++    return {+        "success": False,+        "error": "DWG export failed or not available in this Fusion 360 build.",+        "_hint": _HINT_FORMAT_UNAVAILABLE,+        "data": {+            "hint": "Try fusion_export_dxf or fusion_export_step instead.",+            "alternatives": ["fusion_export_dxf", "fusion_export_step"],+        },+    }+++def handle_export_iges(app: adsk.core.Application, args: dict) -> dict:+    """Export the active design as an IGES file (.igs/.iges).++    Legacy CAD interchange format. Still used by some older CAD systems+    and manufacturing tools. STEP is preferred for modern workflows.++    Args:+        outputPath: Full path for the output .igs file (required).+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        return {"success": False, "error": "No outputPath specified", "_hint": _HINT_NO_OUTPUT_PATH}++    design = _get_active_design(app)+    if not design:+        return _no_design_error()++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    if os.path.exists(output_path):+        try:+            os.remove(output_path)+        except PermissionError:+            return {+                "success": False,+                "error": f"Cannot overwrite {output_path} — file is locked.",+                "_hint": _HINT_FILE_LOCKED,+                "data": {"outputPath": output_path},+            }++    export_mgr = design.exportManager+    try:+        options = export_mgr.createIGESExportOptions(output_path)+        result = export_mgr.execute(options)+        if result and os.path.exists(output_path):+            return _export_success("IGES", output_path,+                                   "Legacy CAD interchange — STEP is preferred for modern use. ")+    except (AttributeError, Exception):+        pass++    return {+        "success": False,+        "error": "IGES export failed or not available in this Fusion 360 build.",+        "_hint": _HINT_FORMAT_UNAVAILABLE,+        "data": {+            "hint": "Try fusion_export_step instead (modern replacement for IGES).",+            "alternatives": ["fusion_export_step"],+        },+    }+++def handle_export_obj(app: adsk.core.Application, args: dict) -> dict:+    """Export the active design as an OBJ file (.obj).++    Wavefront OBJ — simple mesh format widely supported by 3D viewers,+    game engines, and DCC tools. No materials or hierarchy.++    Args:+        outputPath: Full path for the output .obj file (required).+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        return {"success": False, "error": "No outputPath specified", "_hint": _HINT_NO_OUTPUT_PATH}++    design = _get_active_design(app)+    if not design:+        return _no_design_error()++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    if os.path.exists(output_path):+        try:+            os.remove(output_path)+        except PermissionError:+            return {+                "success": False,+                "error": f"Cannot overwrite {output_path} — file is locked.",+                "_hint": _HINT_FILE_LOCKED,+                "data": {"outputPath": output_path},+            }++    export_mgr = design.exportManager+    try:+        options = export_mgr.createOBJExportOptions(output_path)+        result = export_mgr.execute(options)+        if result and os.path.exists(output_path):+            return _export_success("OBJ", output_path,+                                   "Simple mesh format — opens in Blender, Unity, etc. ")+    except (AttributeError, Exception):+        pass++    return {+        "success": False,+        "error": "OBJ export failed or not available in this Fusion 360 build.",+        "_hint": _HINT_FORMAT_UNAVAILABLE,+        "data": {+            "hint": "Try fusion_export_stl or fusion_export_usdz instead.",+            "alternatives": ["fusion_export_stl", "fusion_export_usdz"],+        },+    }+++def handle_export_sat(app: adsk.core.Application, args: dict) -> dict:+    """Export the active design as a SAT file (.sat).++    ACIS SAT — solid modeling kernel format. Used by SolidWorks,+    SpaceClaim, and other ACIS-based CAD tools.++    Args:+        outputPath: Full path for the output .sat file (required).+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        return {"success": False, "error": "No outputPath specified", "_hint": _HINT_NO_OUTPUT_PATH}++    design = _get_active_design(app)+    if not design:+        return _no_design_error()++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    if os.path.exists(output_path):+        try:+            os.remove(output_path)+        except PermissionError:+            return {+                "success": False,+                "error": f"Cannot overwrite {output_path} — file is locked.",+                "_hint": _HINT_FILE_LOCKED,+                "data": {"outputPath": output_path},+            }++    export_mgr = design.exportManager+    try:+        options = export_mgr.createSATExportOptions(output_path)+        result = export_mgr.execute(options)+        if result and os.path.exists(output_path):+            return _export_success("SAT", output_path,+                                   "ACIS solid modeling format — opens in SolidWorks, SpaceClaim. ")+    except (AttributeError, Exception):+        pass++    return {+        "success": False,+        "error": "SAT export failed or not available in this Fusion 360 build.",+        "_hint": _HINT_FORMAT_UNAVAILABLE,+        "data": {+            "hint": "Try fusion_export_step instead.",+            "alternatives": ["fusion_export_step"],+        },+    }+++def handle_export_skp(app: adsk.core.Application, args: dict) -> dict:+    """Export the active design as a SketchUp file (.skp).++    SketchUp format — popular for architectural visualization and+    simple 3D modeling.++    Args:+        outputPath: Full path for the output .skp file (required).+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        return {"success": False, "error": "No outputPath specified", "_hint": _HINT_NO_OUTPUT_PATH}++    design = _get_active_design(app)+    if not design:+        return _no_design_error()++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    if os.path.exists(output_path):+        try:+            os.remove(output_path)+        except PermissionError:+            return {+                "success": False,+                "error": f"Cannot overwrite {output_path} — file is locked.",+                "_hint": _HINT_FILE_LOCKED,+                "data": {"outputPath": output_path},+            }++    export_mgr = design.exportManager+    try:+        options = export_mgr.createSKPExportOptions(output_path)+        result = export_mgr.execute(options)+        if result and os.path.exists(output_path):+            return _export_success("SKP", output_path,+                                   "SketchUp format — opens in SketchUp, Trimble viewers. ")+    except (AttributeError, Exception):+        pass++    return {+        "success": False,+        "error": "SketchUp export failed or not available in this Fusion 360 build.",+        "_hint": _HINT_FORMAT_UNAVAILABLE,+        "data": {+            "hint": "Try fusion_export_step or fusion_export_stl instead.",+            "alternatives": ["fusion_export_step", "fusion_export_stl"],+        },+    }
addin/AdomBridge/commands/import_file.pyadded+107
@@ -0,0 +1,107 @@+"""Import file command — open STEP, IGES, SAT, STL, etc. into the active design."""++import adsk.core+import adsk.fusion+from pathlib import Path++SUPPORTED_EXTENSIONS = {+    ".step", ".stp",+    ".iges", ".igs",+    ".sat",+    ".sab",+    ".smb",+    ".smt",+    ".f3d", ".f3z",+    ".stl",+    ".3mf",+    ".obj",+}+++def handle_import_file(app: adsk.core.Application, args: dict) -> dict:+    """Import a file into Fusion 360 using the native import API.++    Args:+        args: Dict with:+            - filePath: Full path to the file to import (required).+    """+    file_path = args.get("filePath", "")+    if not file_path:+        return {"success": False, "error": "No filePath specified"}++    path = Path(file_path)+    if not path.exists():+        return {+            "success": False,+            "error": f"File not found: {file_path}",+            "_hint": "The path may exist on Docker but not on the Windows host. Use push_file to copy from Docker first, or verify the host-side path.",+        }++    ext = path.suffix.lower()+    if ext not in SUPPORTED_EXTENSIONS:+        return {+            "success": False,+            "error": f"Unsupported file type: {ext}. Supported: {', '.join(sorted(SUPPORTED_EXTENSIONS))}",+            "_hint": "Use fusion_import_electronics for .fsch/.fbrd/.flbr electronics files, or verify the extension is one of the 3D formats Fusion supports.",+        }++    import_mgr = app.importManager++    try:+        # Select the right import options based on file type+        if ext in (".step", ".stp"):+            options = import_mgr.createSTEPImportOptions(str(path))+        elif ext in (".iges", ".igs"):+            options = import_mgr.createIGESImportOptions(str(path))+        elif ext in (".sat", ".sab"):+            options = import_mgr.createSATImportOptions(str(path))+        elif ext in (".smb", ".smt"):+            options = import_mgr.createSMTImportOptions(str(path))+        elif ext in (".f3d", ".f3z"):+            options = import_mgr.createFusionArchiveImportOptions(str(path))+        elif ext == ".stl":+            options = import_mgr.createSTLImportOptions(str(path))+        elif ext == ".3mf":+            options = import_mgr.createC3MFImportOptions(str(path))+        elif ext == ".obj":+            options = import_mgr.createOBJImportOptions(str(path))+        else:+            return {+                "success": False,+                "error": f"No import handler for {ext}",+                "_hint": "Use fusion_import_electronics for .fsch/.fbrd/.flbr electronics files, or verify the extension is one of the 3D formats Fusion supports.",+            }++        # Always import to a new document — importToTarget fails on Part Designs+        # because "Part Design documents can only contain one component".+        # importToNewDocument opens the file in its own document tab, which is+        # the expected behavior (like File > Open).+        doc = import_mgr.importToNewDocument(options)+        if not doc:+            return {+                "success": False,+                "error": f"Import returned null for {path.name}",+                "_hint": "Call fusion_screenshot_fusion to check for a blocking dialog (e.g. unit prompt), then fusion_send_key with 'enter' to accept defaults, then retry.",+            }++        # Activate the newly imported document so subsequent commands work on it+        doc.activate()++        # Verify it's now the active document+        active_doc = app.activeDocument+        doc_name = active_doc.name if active_doc else "Unknown"++        return {+            "success": True,+            "output": f"Imported {path.name} into Fusion 360.",+            "data": {+                "document": doc_name,+            },+        }++    except Exception as e:+        return {+            "success": False,+            "error": f"Import failed: {e}",+            "_hint": "Call fusion_screenshot to check for a modal dialog, dismiss with fusion_send_key escape, then retry.",+        }
addin/AdomBridge/commands/manufacturing.pyadded+1185
@@ -0,0 +1,1185 @@+"""Manufacturing export commands — Gerbers, BOM, CPL for PCB fabrication and assembly.++These commands extract manufacturing data from the open PCB board in Fusion 360's+Electronics workspace and write industry-standard output files:+  - Gerbers (RS-274X) + Excellon drill files via EAGLE CAM processor+  - BOM (Bill of Materials) CSV for component purchasing+  - CPL (Component Placement List) CSV for pick-and-place assembly+  - Design rules (DRU) injection for Adom's InstapcbPCB manufacturing capabilities++All three export commands require a .brd board to be open in PCB Editor.++IMPORTANT — EAGLE "Overwrite?" dialog:+  EAGLE's EXPORT commands open a blocking confirmation dialog if the output+  file already exists. This freezes Fusion's UI thread and crashes the add-in.+  Always use _safe_eagle_export() which deletes the file first and runs+  SET CONFIRM YES before any EAGLE export command.+"""++import adsk.core+import os+import csv+import html+import io+import json+import tempfile+import time+import xml.etree.ElementTree as ET+import zipfile+++def _safe_eagle_export(app, eagle_cmd: str, output_file: str) -> dict:+    """Run an EAGLE export command safely, avoiding the 'Overwrite?' dialog.++    EAGLE's EXPORT commands open a blocking confirmation dialog if the output+    file already exists. This helper:+      1. Deletes the target file if it exists+      2. Runs SET CONFIRM YES to suppress any remaining dialogs+      3. Executes the export command++    Returns a dict with 'deletedExisting' flag so the caller can include it+    in response data for AI debugging context.+    """+    result = {"deletedExisting": False}+    if os.path.exists(output_file):+        os.remove(output_file)+        result["deletedExisting"] = True+    app.executeTextCommand("Electron.run SET CONFIRM YES")+    app.executeTextCommand(f"Electron.run {eagle_cmd}")+    return result+++def _get_board_xml(app: adsk.core.Application) -> str:+    """Get board info XML from the current PCB layout via Electron.boardInfo."""+    board_info_path = os.path.join(tempfile.gettempdir(), "adom_mfg_board_info.xml")++    try:+        app.executeTextCommand(f"Electron.boardInfo {board_info_path}")+    except Exception as e:+        err_msg = str(e)+        if "not pcb" in err_msg.lower():+            ws = "unknown"+            try:+                ws = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+            except Exception:+                pass+            raise RuntimeError(+                f"No board open (current workspace: {ws}). "+                "Open a .brd file first with fusion_open_board."+            )+        raise RuntimeError(f"boardInfo failed: {e}")++    # Read the output file (Fusion writes UTF-16 LE BOM)+    for enc in ("utf-16", "utf-8-sig", "utf-8"):+        try:+            with open(board_info_path, "r", encoding=enc) as f:+                return f.read()+        except (UnicodeDecodeError, UnicodeError):+            continue++    raise RuntimeError("Failed to decode boardInfo XML output.")+++def _parse_components(xml_str: str) -> list:+    """Parse component data from boardInfo XML.++    Returns list of dicts with: name, value, package, library, x, y, rotation, side.+    EAGLE rotation format: R0/R90/R180/R270 = top, MR0/MR90/MR180/MR270 = bottom.+    """+    root = ET.fromstring(xml_str)+    components = []++    for lib_group in root.iter("g"):+        lib = lib_group.get("library")+        pkg = lib_group.get("package")+        if not (lib and pkg):+            continue++        for comp in lib_group.findall("g"):+            name = comp.get("name")+            if not name:+                continue++            rot_str = comp.get("rot", "R0")+            # M prefix = mirrored = bottom side+            side = "Bottom" if rot_str.startswith("M") else "Top"+            # Extract numeric rotation+            rot_num = rot_str.replace("M", "").replace("R", "").replace("S", "")+            try:+                rotation = float(rot_num)+            except ValueError:+                rotation = 0.0++            components.append({+                "name": name,+                "value": comp.get("value", ""),+                "package": pkg,+                "library": lib,+                "x": comp.get("x", "0"),+                "y": comp.get("y", "0"),+                "rotation": rotation,+                "side": side,+            })++    return components+++def _parse_attributes(xml_str: str) -> dict:+    """Parse component attributes from boardInfo XML.++    Returns dict of {component_name: {attr_name: attr_value}}.+    Looks for MPN, MANUFACTURER, MOUSER_PN, DIGIKEY_PN, LCSC_PN etc.+    """+    root = ET.fromstring(xml_str)+    attrs = {}++    # Attributes are stored as <attribute> elements within component groups+    for elem in root.iter("attribute"):+        name = elem.get("name", "")+        value = elem.get("value", "")+        # The parent chain should lead us to the component+        # For now, collect all attributes+        if name and value:+            # Try to find parent component name+            parent = elem+            comp_name = None+            for _ in range(5):  # Walk up max 5 levels+                parent = None  # ET doesn't have parent refs, use different approach+                break+            if name not in attrs:+                attrs[name] = value++    return attrs+++# ─── BOM Export ───────────────────────────────────────────────────────────++def handle_export_bom(app: adsk.core.Application, args: dict) -> dict:+    """Export Bill of Materials (BOM) from the open PCB board.++    Generates a CSV with component values, quantities, and designators —+    suitable for ordering from Mouser, Digi-Key, or LCSC.++    Two approaches combined:+      1. EAGLE's EXPORT PARTLIST for raw parts data+      2. boardInfo XML parsing for coordinates and grouping++    Args:+        outputPath: File path for the output CSV (default: C:/tmp/adom-bom.csv)+        grouped: If true (default), group identical parts by value+package.+                 If false, list every individual component.+    """+    output_path = args.get("outputPath", "C:/tmp/adom-bom.csv")+    grouped = args.get("grouped", True)++    # Ensure output directory exists+    os.makedirs(os.path.dirname(output_path), exist_ok=True)++    # Also try EXPORT PARTLIST for additional attribute data+    partlist_path = os.path.join(tempfile.gettempdir(), "adom_partlist.txt")+    partlist_data = {}+    try:+        _safe_eagle_export(app, f"EXPORT PARTLIST '{partlist_path}'", partlist_path)+        time.sleep(0.5)+        if os.path.exists(partlist_path):+            for enc in ("utf-16", "utf-8-sig", "utf-8", "latin-1"):+                try:+                    with open(partlist_path, "r", encoding=enc) as f:+                        lines = f.readlines()+                    # Parse tab-separated partlist+                    if len(lines) > 1:+                        headers = lines[0].strip().split("\t")+                        for line in lines[1:]:+                            fields = line.strip().split("\t")+                            if len(fields) >= 2:+                                part_name = fields[0].strip()+                                part_info = {}+                                for i, h in enumerate(headers):+                                    if i < len(fields):+                                        part_info[h.strip()] = fields[i].strip()+                                partlist_data[part_name] = part_info+                    break+                except (UnicodeDecodeError, UnicodeError):+                    continue+    except Exception:+        pass  # EXPORT PARTLIST might fail if not in board view; we still have boardInfo++    # Get components from boardInfo XML+    try:+        xml_str = _get_board_xml(app)+    except RuntimeError as e:+        return {+            "success": False,+            "error": str(e),+            "_hint": "Call fusion_show_2d_board or fusion_open_board {\"filePath\":\"...\"} to enter Board Layout, then retry.",+        }++    components = _parse_components(xml_str)+    if not components:+        return {+            "success": False,+            "error": "No components found in board. Is a populated .brd file open?",+            "data": {+                "hint": "The board XML was parsed but contained no component data. "+                        "This usually means the board has no placed components yet.",+                "recoverySteps": [+                    "Verify the board has components placed (not just an empty board outline)",+                    "Switch to schematic and back: fusion_electron_run with 'BOARD' command",+                    "Try fusion_board_info to get raw board data for debugging",+                ],+            },+        }++    # Merge partlist attributes into component data+    for comp in components:+        pl = partlist_data.get(comp["name"], {})+        if pl.get("Value"):+            comp["value"] = pl["Value"]++    if grouped:+        # Group by value + package (same part = same BOM line)+        groups = {}+        for comp in components:+            key = (comp["value"], comp["package"], comp["library"])+            if key not in groups:+                groups[key] = {+                    "value": comp["value"],+                    "package": comp["package"],+                    "library": comp["library"],+                    "designators": [],+                    "quantity": 0,+                }+            groups[key]["designators"].append(comp["name"])+            groups[key]["quantity"] += 1++        # Sort by designator (natural sort: C1, C2, ..., R1, R2, ...)+        rows = sorted(groups.values(), key=lambda g: g["designators"][0])++        # Write grouped BOM CSV+        with open(output_path, "w", newline="", encoding="utf-8") as f:+            writer = csv.writer(f)+            writer.writerow(["Comment", "Designator", "Footprint", "Quantity", "Library"])+            for row in rows:+                writer.writerow([+                    row["value"],+                    " ".join(sorted(row["designators"])),+                    row["package"],+                    row["quantity"],+                    row["library"],+                ])+    else:+        # Ungrouped — one row per component+        with open(output_path, "w", newline="", encoding="utf-8") as f:+            writer = csv.writer(f)+            writer.writerow(["Designator", "Comment", "Footprint", "Library", "Side"])+            for comp in sorted(components, key=lambda c: c["name"]):+                writer.writerow([+                    comp["name"],+                    comp["value"],+                    comp["package"],+                    comp["library"],+                    comp["side"],+                ])++    unique_count = len(rows) if grouped else len(components)+    return {+        "success": True,+        "output": f"BOM exported: {len(components)} components"+                  + (f" in {unique_count} unique parts" if grouped else "")+                  + f" → {output_path}",+        "message": (+            f"Bill of Materials CSV with {unique_count} unique part"+            f"{'s' if unique_count != 1 else ''} and {len(components)} total placements. "+            "Format: Comment, Designator, Footprint, Quantity, Library — "+            "compatible with JLCPCB, PCBWay, Mouser, and Digi-Key."+        ),+        "data": {+            "outputPath": output_path,+            "componentCount": len(components),+            "uniquePartCount": unique_count,+            "grouped": grouped,+            "nextSteps": [+                "Run fusion_export_cpl to generate the pick-and-place CSV",+                "Run fusion_export_gerbers to generate the Gerber fabrication ZIP",+                "Once you have BOM + CPL + Gerbers, upload all three to your PCB fab service",+            ],+            "hint": (+                "If BOM looks incomplete, check that component values are set in the schematic. "+                "Use fusion_board_info for raw structured component data."+            ),+        },+    }+++# ─── CPL / Pick-and-Place Export ──────────────────────────────────────────++def handle_export_cpl(app: adsk.core.Application, args: dict) -> dict:+    """Export Component Placement List (CPL) for pick-and-place assembly.++    Generates a CSV with component centroid positions, rotation, and side —+    the standard format expected by PCBA manufacturers (JLCPCB, PCBWay, etc.).++    Coordinates are in millimeters relative to the board origin.++    Args:+        outputPath: File path for the output CSV (default: C:/tmp/adom-cpl.csv)+        side: Filter by side — "all" (default), "top", or "bottom"+    """+    output_path = args.get("outputPath", "C:/tmp/adom-cpl.csv")+    side_filter = args.get("side", "all").lower()++    os.makedirs(os.path.dirname(output_path), exist_ok=True)++    try:+        xml_str = _get_board_xml(app)+    except RuntimeError as e:+        return {+            "success": False,+            "error": str(e),+            "_hint": "Call fusion_show_2d_board or fusion_open_board {\"filePath\":\"...\"} to enter Board Layout, then retry.",+        }++    components = _parse_components(xml_str)+    if not components:+        return {+            "success": False,+            "error": "No components found in board. Is a populated .brd file open?",+            "data": {+                "hint": "Board has no component placements. CPL requires components to be placed on the board.",+                "recoverySteps": [+                    "Verify the board has components placed (check with fusion_board_info)",+                    "If schematic has components but board doesn't, the board may need updating",+                ],+            },+        }++    # Filter by side if requested+    if side_filter in ("top", "bottom"):+        target = side_filter.capitalize()+        components = [c for c in components if c["side"] == target]++    if not components:+        return {+            "success": False,+            "error": f"No {side_filter}-side components found.",+        }++    # Write CPL CSV (standard JLCPCB/generic format)+    with open(output_path, "w", newline="", encoding="utf-8") as f:+        writer = csv.writer(f)+        writer.writerow(["Designator", "Mid X", "Mid Y", "Layer", "Rotation"])+        for comp in sorted(components, key=lambda c: c["name"]):+            writer.writerow([+                comp["name"],+                comp["x"],+                comp["y"],+                comp["side"],+                comp["rotation"],+            ])++    top_count = sum(1 for c in components if c["side"] == "Top")+    bottom_count = sum(1 for c in components if c["side"] == "Bottom")++    return {+        "success": True,+        "output": f"CPL exported: {len(components)} placements "+                  f"({top_count} top, {bottom_count} bottom) → {output_path}",+        "message": (+            f"Pick-and-place CSV with {len(components)} component placements "+            f"({top_count} top-side, {bottom_count} bottom-side). "+            "Format: Designator, Mid X, Mid Y, Layer, Rotation — "+            "coordinates in mm, compatible with JLCPCB/PCBWay/Adom PCBA."+        ),+        "data": {+            "outputPath": output_path,+            "totalPlacements": len(components),+            "topCount": top_count,+            "bottomCount": bottom_count,+            "sideFilter": side_filter,+            "nextSteps": [+                "Run fusion_export_bom if you haven't already — you need BOM + CPL together",+                "Run fusion_export_gerbers to generate the Gerber fabrication ZIP",+                "Upload BOM + CPL + Gerbers together to your PCBA service for assembly quoting",+            ],+            "hint": (+                "If placement coordinates look wrong, verify the board origin in EAGLE. "+                "Use side='top' or side='bottom' to export only one side for single-sided assembly."+            ),+        },+    }+++# ─── Resource Path Helper ────────────────────────────────────────────────++def _get_resources_dir() -> str:+    """Get the path to the add-in's bundled resources directory.++    Resources (CAM jobs, DRU files, ULP scripts) are bundled at:+      AdomBridge/resources/  (synced to %APPDATA%/.../AdomBridge/resources/)+    """+    # manufacturing.py is at: AdomBridge/commands/manufacturing.py+    # resources are at:       AdomBridge/resources/+    addin_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))+    return os.path.join(addin_root, "resources")+++# ─── Layer Detection ─────────────────────────────────────────────────────++def _detect_layer_count(app: adsk.core.Application) -> dict:+    """Detect if the open board is 2-layer or 4-layer.++    Uses two methods in priority order:+      1. ULP script — runs detect_layers.ulp to inspect copper layers and traces+      2. CAM comparison — exports with both 2-layer and 4-layer CAM jobs,+         compares ZIP sizes to detect inner copper content++    Returns dict with: layerCount, is4Layer, method, copperLayers, details+    """+    resources = _get_resources_dir()+    result = {"layerCount": 2, "is4Layer": False, "method": "default",+              "copperLayers": [1, 16], "details": ""}++    # Method A: ULP script detection+    ulp_path = os.path.join(resources, "ulp", "detect_layers.ulp").replace("\\", "/")+    if os.path.exists(ulp_path):+        try:+            temp_fd, temp_json = tempfile.mkstemp(suffix=".json")+            os.close(temp_fd)+            temp_json = os.path.abspath(temp_json).replace("\\", "/")++            app.executeTextCommand(f"Electron.run RUN '{ulp_path}' '{temp_json}'")++            if os.path.exists(temp_json):+                with open(temp_json, "r") as f:+                    data = json.loads(f.read())+                os.remove(temp_json)++                copper_count = data.get("copperLayerCount", 0)+                layers_list = data.get("layers", [])+                copper_layers = [+                    l["number"] for l in layers_list+                    if l.get("isCopper") and (l["number"] in (1, 16) or l.get("hasTraces"))+                ]+                internal = [l for l in copper_layers if l not in (1, 16)]++                if internal or copper_count > 2:+                    result.update({+                        "layerCount": max(copper_count, 4),+                        "is4Layer": True,+                        "method": "ulp",+                        "copperLayers": copper_layers,+                        "details": f"ULP found {len(internal)} internal routing layer(s): {internal}",+                    })+                else:+                    result.update({+                        "method": "ulp",+                        "copperLayers": copper_layers,+                        "details": f"ULP found {copper_count} copper layers, no internal routing",+                    })+                return result+        except Exception as e:+            result["details"] = f"ULP detection failed: {e}; "++    # Method B: CAM comparison (export both, compare sizes)+    cam_2 = os.path.join(resources, "cam", "jlcpcb-2layers.cam").replace("\\", "/")+    cam_4 = os.path.join(resources, "cam", "jlcpcb-4layers.cam").replace("\\", "/")++    if os.path.exists(cam_2) and os.path.exists(cam_4):+        try:+            tmp_dir = tempfile.gettempdir().replace("\\", "/")+            zip_2 = f"{tmp_dir}/adom_test_2layer.zip"+            zip_4 = f"{tmp_dir}/adom_test_4layer.zip"++            # Export with 2-layer CAM+            app.executeTextCommand(+                f"Electron.run set confirm yes;manufacturing export '{zip_2}' '{cam_2}'"+            )+            size_2 = os.path.getsize(zip_2) if os.path.exists(zip_2) else 0++            # Export with 4-layer CAM+            app.executeTextCommand(+                f"Electron.run set confirm yes;manufacturing export '{zip_4}' '{cam_4}'"+            )+            size_4 = os.path.getsize(zip_4) if os.path.exists(zip_4) else 0++            # Clean up+            for f in (zip_2, zip_4):+                try:+                    os.remove(f)+                except Exception:+                    pass++            if size_2 > 0 and size_4 > 0:+                ratio = size_4 / size_2+                # Adaptive threshold based on file size+                if size_2 > 100_000:+                    threshold = 1.02+                elif size_2 > 50_000:+                    threshold = 1.03+                else:+                    threshold = 1.05++                if ratio > threshold:+                    result.update({+                        "layerCount": 4, "is4Layer": True, "method": "cam_comparison",+                        "details": f"4-layer ZIP is {ratio:.2f}x larger (threshold {threshold})",+                    })+                else:+                    result.update({+                        "method": "cam_comparison",+                        "details": f"4-layer ZIP ratio {ratio:.2f} (< {threshold}), treating as 2-layer",+                    })+                return result+        except Exception as e:+            result["details"] += f"CAM comparison failed: {e}"++    return result+++def handle_detect_layers(app: adsk.core.Application, args: dict) -> dict:+    """Detect the layer count of the open PCB board.++    Uses ULP script and/or CAM comparison to determine if the board is+    2-layer or 4-layer. Useful before gerber export or design rules application.+    """+    # Verify we're in board layout+    try:+        ws = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+    except Exception:+        ws = "unknown"++    if "Board" not in ws and "PCB" not in ws:+        return {+            "success": False,+            "error": f"Not in Board Layout (current: {ws}). Open a .brd file first.",+            "_hint": "Call fusion_show_2d_board or fusion_open_board {\"filePath\":\"...\"} to enter PCB Editor, then retry.",+            "data": {"activeWorkspace": ws},+        }++    detection = _detect_layer_count(app)++    layer_type = f"{detection['layerCount']}-layer"+    return {+        "success": True,+        "output": f"Board detected as {layer_type} ({detection['method']} method). "+                  f"Copper layers: {detection['copperLayers']}",+        "message": (+            f"This is a {layer_type} board. Detection used {detection['method']} method. "+            f"Copper layers found: {detection['copperLayers']}. "+            f"All subsequent manufacturing commands (gerbers, design rules) will auto-select "+            f"the {layer_type} configuration."+        ),+        "data": {+            **detection,+            "activeWorkspace": ws,+            "nextSteps": [+                f"Run fusion_set_design_rules to apply Adom's {layer_type} manufacturing rules",+                f"Run fusion_export_gerbers — auto-selects the {layer_type} CAM job",+                "Run fusion_electron_run with command 'DRC' after applying design rules to check compliance",+            ],+        },+    }+++# ─── Gerber Export ────────────────────────────────────────────────────────++def handle_export_gerbers(app: adsk.core.Application, args: dict) -> dict:+    """Export Gerber manufacturing files from the open PCB board.++    Uses Fusion's CAM processor with bundled JLCPCB-compatible CAM job files+    to produce a ZIP containing industry-standard gerber files:+      - Top/Bottom Copper (.GTL/.GBL)+      - Top/Bottom Silkscreen (.GTO/.GBO)+      - Top/Bottom Solder Mask (.GTS/.GBS)+      - Top/Bottom Paste (.GTP/.GBP)+      - Board Outline (.GKO)+      - Drill file (.XLN)+      - (4-layer boards also get inner copper .G1/.G2)++    Auto-detects 2-layer vs 4-layer boards and selects the right CAM job.++    Args:+        outputDir: Directory for the output ZIP (default: C:/tmp/adom-gerbers/)+        boardName: Prefix for the ZIP filename (default: from active document)+        layers: Force layer count — "2" or "4" (default: auto-detect)+    """+    output_dir = args.get("outputDir", "C:/tmp/adom-gerbers")+    board_name = args.get("boardName", "")+    force_layers = args.get("layers", "auto")++    os.makedirs(output_dir, exist_ok=True)++    # Verify board layout+    try:+        ws = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+    except Exception:+        ws = "unknown"++    if "Board" not in ws and "PCB" not in ws:+        return {+            "success": False,+            "error": f"Not in Board Layout (current: {ws}). "+                     "Open a .brd file in PCB Editor first.",+            "_hint": "Call fusion_show_2d_board to switch to PCB Editor, then retry.",+            "data": {+                "activeWorkspace": ws,+                "hint": "Use fusion_show_2d_board to switch to PCB Editor.",+            },+        }++    # Get board name+    if not board_name:+        try:+            doc = app.activeDocument+            if doc:+                board_name = doc.name.replace(".brd", "").replace(".fsch", "").replace(" ", "_")+            else:+                board_name = "board"+        except Exception:+            board_name = "board"++    # Detect layer count+    if force_layers in ("2", "4"):+        layer_count = int(force_layers)+        detection_method = "manual"+    else:+        detection = _detect_layer_count(app)+        layer_count = detection["layerCount"]+        detection_method = detection["method"]++    # Select CAM job file+    resources = _get_resources_dir()+    cam_file = os.path.join(+        resources, "cam", f"jlcpcb-{layer_count}layers.cam"+    ).replace("\\", "/")++    if not os.path.exists(cam_file):+        return {+            "success": False,+            "error": f"CAM job file not found: {cam_file}",+            "data": {+                "hint": "Ensure the resources/cam/ directory contains jlcpcb-2layers.cam "+                        "and jlcpcb-4layers.cam. Run install_addin.py to sync.",+            },+        }++    # Build output ZIP path+    zip_path = os.path.join(output_dir, f"{board_name}_gerbers.zip").replace("\\", "/")++    # Delete existing ZIP to avoid overwrite dialog+    if os.path.exists(zip_path):+        try:+            os.remove(zip_path)+        except Exception:+            pass++    # Execute the CAM export — this is the working command from AdomHelperJoe+    try:+        export_cmd = f"Electron.run set confirm yes;manufacturing export '{zip_path}' '{cam_file}'"+        app.executeTextCommand(export_cmd)+    except Exception as e:+        return {+            "success": False,+            "error": f"Manufacturing export failed: {e}",+            "_hint": "Call fusion_show_2d_board to ensure 2D PCB Editor is active (not 3D view), then retry.",+            "data": {+                "command": f"manufacturing export '{zip_path}' '{cam_file}'",+                "hint": "Ensure you are in the PCB Editor (not schematic or 3D view).",+            },+        }++    # Verify output+    if not os.path.exists(zip_path):+        return {+            "success": False,+            "error": "CAM export command ran but ZIP was not created.",+            "_hint": "Call fusion_show_2d_board to ensure 2D PCB Editor is active, then retry.",+            "data": {+                "zipPath": zip_path,+                "camFile": cam_file,+                "layerCount": layer_count,+                "hint": "Try switching to 2D board view with fusion_show_2d_board, "+                        "then retry.",+            },+        }++    zip_size = os.path.getsize(zip_path)++    # List ZIP contents for the AI+    gerber_files = []+    try:+        with zipfile.ZipFile(zip_path, "r") as zf:+            for info in zf.infolist():+                if not info.is_dir():+                    gerber_files.append({+                        "name": info.filename,+                        "size": info.file_size,+                    })+    except Exception:+        pass++    file_names = [f["name"] for f in gerber_files]+    return {+        "success": True,+        "output": (+            f"Gerbers exported: {len(gerber_files)} files in ZIP "+            f"({zip_size // 1024} KB) → {zip_path}"+        ),+        "message": (+            f"Gerber ZIP created for {layer_count}-layer board '{board_name}' with "+            f"{len(gerber_files)} files ({zip_size // 1024} KB). "+            f"Contains: {', '.join(file_names[:5])}{'...' if len(file_names) > 5 else ''}. "+            "This ZIP is ready for upload to any PCB fabrication service."+        ),+        "data": {+            "zipPath": zip_path,+            "zipSizeKB": zip_size // 1024,+            "layerCount": layer_count,+            "detectionMethod": detection_method,+            "boardName": board_name,+            "files": gerber_files,+            "fileCount": len(gerber_files),+            "nextSteps": [+                "Run fusion_export_bom to generate the Bill of Materials CSV",+                "Run fusion_export_cpl to generate the Component Placement List CSV",+                "Once you have Gerbers + BOM + CPL, upload all three to your PCBA service",+                "Use pull_file to transfer the ZIP back to Docker for ordering",+            ],+            "hint": (+                f"Auto-detected {layer_count}-layer board via {detection_method}. "+                "If wrong, force layer count with layers='2' or layers='4'."+            ),+        },+    }+++# ─── Design Rules (DRU) ──────────────────────────────────────────────────++def _parse_edru_description(edru_path: str) -> str:+    """Parse an .edru file and extract its human-readable description."""+    try:+        tree = ET.parse(edru_path)+        root = tree.getroot()+        desc_elem = root.find(".//description[@language='en']")+        if desc_elem is not None and desc_elem.text:+            return html.unescape(desc_elem.text).strip()+    except Exception:+        pass+    return ""+++def handle_set_design_rules(app: adsk.core.Application, args: dict) -> dict:+    """Set PCB design rules in the open board to match Adom's manufacturing capabilities.++    Loads a bundled .edru design rules file via EAGLE's `drc load` command.+    The .edru files are industry-tested rules from JLCPCB, adapted for Adom's+    InstapcbPCB manufacturing process.++    Auto-detects 2-layer vs 4-layer boards and loads the appropriate rule set.++    Args:+        action: "apply" (default) to load Adom rules, "export" to save current rules,+                "show" to display capabilities without changing anything+        layers: "auto" (default), "2", or "4" — which rule set to load+        outputPath: For "export" — path to save current .dru file+    """+    action = args.get("action", "apply")+    force_layers = args.get("layers", "auto")+    resources = _get_resources_dir()++    if action == "show":+        # Show capabilities from the 2-layer .edru description+        edru_2 = os.path.join(resources, "dru", "Adom-InstaPCB-2-Layer.edru")+        edru_4 = os.path.join(resources, "dru", "Adom-InstaPCB-4-Layer.edru")+        desc_2 = _parse_edru_description(edru_2) if os.path.exists(edru_2) else ""+        desc_4 = _parse_edru_description(edru_4) if os.path.exists(edru_4) else ""++        return {+            "success": True,+            "output": "Adom InstaPCB design rules (from bundled .edru files)",+            "data": {+                "2layer_rules": desc_2 or "2-layer .edru file not found",+                "4layer_rules": desc_4 or "4-layer .edru file not found",+                "nextSteps": [+                    "Use fusion_set_design_rules with action='apply' to load rules into the board",+                    "Layer count is auto-detected, or force with layers='2' or layers='4'",+                ],+            },+        }++    # Verify we're in board layout+    try:+        ws = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+    except Exception:+        ws = "unknown"++    if "Board" not in ws and "PCB" not in ws:+        return {+            "success": False,+            "error": f"Not in Board Layout (current: {ws}). Open a .brd file first.",+            "_hint": "Call fusion_show_2d_board or fusion_open_board {\"filePath\":\"...\"} to enter PCB Editor, then retry.",+            "data": {"activeWorkspace": ws},+        }++    if action == "export":+        output_path = args.get("outputPath", "C:/tmp/current-design-rules.dru")+        os.makedirs(os.path.dirname(output_path), exist_ok=True)+        try:+            app.executeTextCommand(f"Electron.run DRC SAVE '{output_path}'")+            time.sleep(0.5)+            if os.path.exists(output_path):+                return {+                    "success": True,+                    "output": f"Current design rules exported to {output_path}",+                    "data": {"outputPath": output_path},+                }+            return {+                "success": False,+                "error": "DRC SAVE did not produce output.",+            }+        except Exception as e:+            return {"success": False, "error": f"DRC SAVE failed: {e}"}++    # action == "apply": Load bundled .edru design rules+    if force_layers in ("2", "4"):+        layer_count = int(force_layers)+        detection_method = "manual"+    else:+        detection = _detect_layer_count(app)+        layer_count = detection["layerCount"]+        detection_method = detection["method"]++    # Resolve the .edru file+    edru_filename = f"Adom-InstaPCB-{layer_count}-Layer.edru"+    edru_path = os.path.join(resources, "dru", edru_filename)++    if not os.path.exists(edru_path):+        return {+            "success": False,+            "error": f"Design rules file not found: {edru_path}",+            "data": {+                "hint": "Ensure resources/dru/ contains the .edru files. "+                        "Run install_addin.py to sync.",+            },+        }++    edru_path_fwd = edru_path.replace("\\", "/")++    # Load via EAGLE's drc load command (lowercase — this is the correct syntax)+    try:+        app.executeTextCommand(f"Electron.run drc load '{edru_path_fwd}'")+    except Exception as e:+        return {+            "success": False,+            "error": f"Failed to load design rules: {e}",+            "data": {"edruPath": edru_path_fwd},+        }++    # Parse description for the success message+    description = _parse_edru_description(edru_path)++    return {+        "success": True,+        "output": (+            f"Adom {layer_count}-layer design rules loaded from {edru_filename}. "+            f"Detection method: {detection_method}."+        ),+        "message": (+            f"Adom InstaPCB {layer_count}-Layer design rules are now active. "+            f"Min trace: 0.08mm (3mil), min spacing: 0.08mm (3mil), min drill: 0.2mm (8mil). "+            f"Rule violations will now show as DRC markers in the board editor."+        ),+        "data": {+            "edruFile": edru_filename,+            "edruPath": edru_path_fwd,+            "layerCount": layer_count,+            "detectionMethod": detection_method,+            "description": description,+            "activeWorkspace": ws,+            "nextSteps": [+                "Run fusion_electron_run with command 'DRC' to check for rule violations",+                "Run fusion_export_gerbers to export Gerber files with the correct CAM job",+                "Run fusion_export_bom and fusion_export_cpl to complete the manufacturing package",+            ],+            "hint": (+                "DRC violations appear as markers in the board. Use fusion_board_info to get "+                "structured DRC data, or fusion_export_board_image with preset 'fabrication' "+                "to visually inspect the result."+            ),+        },+    }+++# ─── Board Image Export (PNG / PDF / layer views) ────────────────────────++# Layer presets for common manufacturing views+LAYER_PRESETS = {+    "all": {+        "description": "All layers visible",+        "command": "DISPLAY ALL",+    },+    "top_copper": {+        "description": "Top copper + pads + vias",+        "layers": [1, 17, 18],+    },+    "bottom_copper": {+        "description": "Bottom copper + pads + vias",+        "layers": [16, 17, 18],+    },+    "top_silkscreen": {+        "description": "Top silkscreen + names",+        "layers": [21, 25],+    },+    "bottom_silkscreen": {+        "description": "Bottom silkscreen + names",+        "layers": [22, 26],+    },+    "top_soldermask": {+        "description": "Top solder mask openings",+        "layers": [29],+    },+    "bottom_soldermask": {+        "description": "Bottom solder mask openings",+        "layers": [30],+    },+    "top_paste": {+        "description": "Top paste/stencil openings",+        "layers": [31],+    },+    "bottom_paste": {+        "description": "Bottom paste/stencil openings",+        "layers": [32],+    },+    "board_outline": {+        "description": "Board outline (dimension layer)",+        "layers": [20],+    },+    "drill": {+        "description": "Drill holes + vias",+        "layers": [44, 45, 17, 18],+    },+    "assembly_top": {+        "description": "Top assembly view — copper + silk + outline + names",+        "layers": [1, 17, 18, 20, 21, 25, 51],+    },+    "assembly_bottom": {+        "description": "Bottom assembly view — copper + silk + outline + names",+        "layers": [16, 17, 18, 20, 22, 26, 52],+    },+    "fabrication": {+        "description": "Full fabrication view — all copper + mask + silk + outline",+        "layers": [1, 16, 17, 18, 19, 20, 21, 22, 25, 26, 29, 30, 51],+    },+}+++def handle_export_board_image(app: adsk.core.Application, args: dict) -> dict:+    """Export a PNG image of the open PCB board with configurable layer visibility.++    Uses EAGLE's EXPORT IMAGE command to render the board at a specified DPI.+    Layer presets make it easy to export common manufacturing views (silkscreen,+    copper, outline, etc.) without manually toggling layers.++    After export, restores the previous layer visibility.++    Args:+        outputPath: File path for the output image (default: C:/tmp/adom-board.png)+        dpi: Resolution in dots per inch (default: 300, max: 600)+        preset: Layer preset name — one of:+            "all", "top_copper", "bottom_copper", "top_silkscreen",+            "bottom_silkscreen", "top_soldermask", "bottom_soldermask",+            "top_paste", "bottom_paste", "board_outline", "drill",+            "assembly_top", "assembly_bottom", "fabrication"+        layers: Custom layer numbers (list of ints) — overrides preset if provided+        monochrome: If true, export in black & white (default: false)+        mirror: If true, mirror the image horizontally (default: false)+        listPresets: If true, return available presets instead of exporting+    """+    # List presets mode+    if args.get("listPresets", False):+        preset_list = {k: v["description"] for k, v in LAYER_PRESETS.items()}+        return {+            "success": True,+            "output": f"{len(preset_list)} layer presets available",+            "data": {"presets": preset_list},+        }++    output_path = args.get("outputPath", "C:/tmp/adom-board.png")+    dpi = min(int(args.get("dpi", 300)), 600)+    preset = args.get("preset", "all")+    custom_layers = args.get("layers", None)+    monochrome = args.get("monochrome", False)+    mirror_img = args.get("mirror", False)++    os.makedirs(os.path.dirname(output_path), exist_ok=True)++    # Verify we're in an electronics editor+    try:+        ws = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+    except Exception:+        ws = "unknown"++    # Works in Board Layout and Schematic Editor+    is_electronics = False+    try:+        app.executeTextCommand("Electron.run DISPLAY")+        is_electronics = True+    except Exception:+        pass++    if not is_electronics:+        return {+            "success": False,+            "error": f"Not in Electronics editor (current: {ws}). "+                     "Open a .brd or .sch file first.",+            "_hint": "Call fusion_open_board {\"filePath\":\"...\"} or fusion_show_2d_board to enter the PCB editor, then retry.",+            "data": {+                "activeWorkspace": ws,+                "hint": "Use fusion_open_board or fusion_show_2d_board to enter the PCB editor.",+                "recoverySteps": [+                    "Open a .brd file with fusion_open_board",+                    "Or switch to 2D board view with fusion_show_2d_board",+                    "Then retry this command",+                ],+            },+        }++    # Save current layer state (we'll restore it after export)+    # There's no direct way to query current DISPLAY state, so we'll+    # just restore ALL after export.++    # Silkscreen registration: when exporting a silkscreen layer, fit the view to+    # the BOARD OUTLINE (layer 20) rather than the silk content. The silk content's+    # bbox is smaller than (and offset within) the board, so a content-fit PNG can't+    # be UV-mapped to the board's XY bbox by a downstream overlay (e.g. OCCT+    # apply_silkscreen). We show the outline ONLY to key WINDOW FIT to the board+    # bbox, then hide it before EXPORT so it's not baked into the silk PNG.+    # (Pixel-exact bbox crop + bottom-side mirror are done container-side, where an+    # image lib is available — Fusion's add-in Python has none.)+    silk_export_display = None  # set for silk presets: the silk-only DISPLAY used for EXPORT++    # Set layer visibility+    if custom_layers:+        layer_nums = " ".join(str(l) for l in custom_layers)+        display_cmd = f"DISPLAY NONE; DISPLAY {layer_nums}"+    elif preset in LAYER_PRESETS:+        p = LAYER_PRESETS[preset]+        if "command" in p:+            display_cmd = p["command"]+        else:+            layer_nums = " ".join(str(l) for l in p["layers"])+            if preset in ("top_silkscreen", "bottom_silkscreen"):+                # Fit with the outline visible; export with silk only.+                display_cmd = f"DISPLAY NONE; DISPLAY {layer_nums} 20"+                silk_export_display = f"DISPLAY NONE; DISPLAY {layer_nums}"+            else:+                display_cmd = f"DISPLAY NONE; DISPLAY {layer_nums}"+    else:+        return {+            "success": False,+            "error": f"Unknown preset '{preset}'. Use listPresets to see available options.",+            "_hint": "Call fusion_export_board_image with {\"listPresets\": true} to see valid preset names.",+            "data": {"availablePresets": list(LAYER_PRESETS.keys())},+        }++    try:+        # Set layers — split semicolon-separated commands into individual calls+        for cmd in display_cmd.split(";"):+            cmd = cmd.strip()+            if cmd:+                app.executeTextCommand(f"Electron.run {cmd}")+                time.sleep(0.2)+        time.sleep(0.3)++        # Zoom to fit. For silk presets the board outline (layer 20) is visible+        # here, so WINDOW FIT keys the view to the board's XY bbox.+        app.executeTextCommand("Electron.run WINDOW FIT")+        time.sleep(0.3)++        # Silk: hide the outline now (keep the same window extent) so the EXPORT+        # captures only silkscreen, board-bbox-keyed.+        if silk_export_display:+            for cmd in silk_export_display.split(";"):+                cmd = cmd.strip()+                if cmd:+                    app.executeTextCommand(f"Electron.run {cmd}")+                    time.sleep(0.15)+            time.sleep(0.2)++        # Delete existing file to avoid overwrite dialog+        output_path_escaped = output_path.replace("\\", "/")+        if os.path.exists(output_path_escaped):+            os.remove(output_path_escaped)++        # Export image+        export_cmd = f"EXPORT IMAGE '{output_path_escaped}' {dpi}"+        if monochrome:+            export_cmd = f"EXPORT IMAGE '{output_path_escaped}' MONOCHROME {dpi}"++        app.executeTextCommand(f"Electron.run SET CONFIRM YES")+        app.executeTextCommand(f"Electron.run {export_cmd}")+        time.sleep(1.0)++    except Exception as e:+        # Restore layers before returning error+        try:+            app.executeTextCommand("Electron.run DISPLAY ALL")+        except Exception:+            pass+        return {+            "success": False,+            "error": f"Export failed: {e}",+            "data": {+                "activeWorkspace": ws,+                "preset": preset,+                "hint": "EXPORT IMAGE may fail if no board/schematic content is visible. "+                        "Try WINDOW FIT first, or use a different layer preset.",+            },+        }++    # Restore all layers visible+    try:+        app.executeTextCommand("Electron.run DISPLAY ALL")+    except Exception:+        pass++    # Verify output file exists+    if not os.path.exists(output_path):+        return {+            "success": False,+            "error": f"EXPORT IMAGE did not create file at {output_path}. "+                     "The command may not be supported in this context.",+            "_hint": "Call fusion_show_2d_board first to ensure 2D PCB Editor is active, then retry.",+        }++    file_size = os.path.getsize(output_path)+    preset_desc = LAYER_PRESETS.get(preset, {}).get("description", preset) if not custom_layers else f"custom layers: {custom_layers}"++    return {+        "success": True,+        "output": f"Board image exported ({preset_desc}) at {dpi} DPI → {output_path}",+        "message": (+            f"PNG image of {preset_desc} at {dpi} DPI ({file_size // 1024} KB). "+            "Use pull_file to transfer to Docker for inspection or documentation."+        ),+        "data": {+            "outputPath": output_path,+            "dpi": dpi,+            "preset": preset if not custom_layers else "custom",+            "presetDescription": preset_desc,+            "fileSize": file_size,+            "fileSizeKB": file_size // 1024,+            "monochrome": monochrome,+            "activeWorkspace": ws,+            "nextSteps": [+                "Use pull_file to transfer the image to Docker for review",+                "Export more views: 'assembly_top', 'assembly_bottom', 'top_copper', 'board_outline'",+                "For manufacturing: also export gerbers, BOM, and CPL",+            ],+            "hint": (+                "Common presets: 'assembly_top' (component placement review), "+                "'top_copper' (routing check), 'fabrication' (full fab view), "+                "'board_outline' (dimensions check)."+            ),+        },+    }
addin/AdomBridge/commands/modeling.pyadded+68
@@ -0,0 +1,68 @@+"""In-app parametric modeling for the Adom Bridge.++`run_modeling_script` executes a Python snippet against the live Fusion 360+modeling API (adsk.fusion) inside the user's open Fusion session. This is the+FREE, immediate path to programmatic CAD (sketches, extrudes, components,+parameters) — as opposed to the APS Fusion Automation API, which runs headless+in the cloud but BILLS per processing hour. Use this to build parametric parts+(e.g. a JST connector) from a script.++The snippet runs ON THE MAIN THREAD (the add-in marshals every command through a+CustomEvent), which is required by the Fusion modeling API. The snippet's globals+include `adsk`, `app`, `ui`, and a `design` (the active Fusion Design, created if+none is open). Anything the snippet `print()`s is captured; set a top-level+`result` variable to return structured data.+"""++import io+import contextlib+import traceback++import adsk.core+import adsk.fusion+++def handle_run_modeling_script(app: adsk.core.Application, args: dict) -> dict:+    script = args.get("script") or args.get("code") or ""+    if not script:+        return {"success": False, "error": "No script provided.",+                "_hint": "Pass {\"script\": \"<python using adsk.fusion>\"}. Globals available: "+                         "adsk, app, ui, design (active Design, created if none open)."}++    ui = app.userInterface+    # Ensure there's a design to model into — create a fresh Fusion design if the+    # active product isn't one (e.g. the user is on the data panel / an empty tab).+    design = adsk.fusion.Design.cast(app.activeProduct)+    if not design:+        app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)+        design = adsk.fusion.Design.cast(app.activeProduct)+    if not design:+        return {"success": False, "error": "Could not obtain a Fusion Design to model into.",+                "_hint": "Open or create a Fusion design document, then retry. A read-only/expired "+                         "Fusion can still MODEL in memory; only saving to the cloud is blocked."}++    ns = {+        "adsk": adsk,+        "app": app,+        "ui": ui,+        "design": design,+        "__name__": "__adom_modeling__",+    }+    buf = io.StringIO()+    try:+        with contextlib.redirect_stdout(buf):+            exec(script, ns)+    except Exception as e:+        return {"success": False, "error": str(e),+                "data": {"traceback": traceback.format_exc(), "stdout": buf.getvalue()},+                "_hint": "Modeling-script error (a code/geometry problem, NOT the Fusion license). "+                         "Read-only Fusion still creates geometry in memory; only cloud-save is blocked."}++    res = ns.get("result")+    # Keep the return JSON-safe.+    if not isinstance(res, (str, int, float, bool, dict, list, type(None))):+        res = str(res)+    out = buf.getvalue().strip()+    return {"success": True,+            "output": out or "Modeling script ran successfully.",+            "data": {"result": res, "documentName": app.activeDocument.name if app.activeDocument else None}}
addin/AdomBridge/commands/open_electronics_file.pyadded+605
@@ -0,0 +1,605 @@+"""Open electronics files in Fusion 360's Electronics workspace.++Each file type gets its own command for clarity:+  fusion_open_schematic  — .sch files → Schematic Editor+  fusion_open_board      — .brd files → Board Layout editor+  fusion_show_3d_board   — switches Board Layout → 3D PCB view++All use Document.newDesignFromLocal which reliably opens these file types+and switches to the correct Electronics sub-workspace automatically.++fusion_open_lbr (in open_lbr.py) handles .lbr library files.++Fusion 360 Electronics projects are cloud-based (not .epr files like standalone EAGLE).+The project is the Fusion document itself. Open a schematic or board to work with a design.+"""++import adsk.core+import os+import time+++def _open_local_document(app, file_path: str):+    """Run Document.newDesignFromLocal for a path that MAY CONTAIN SPACES.++    BUG (Drew's agent, issue #196, 2026-07-16): executeTextCommand is a SPACE-DELIMITED+    command string, so an unquoted path like+      C:/Users/drew/Downloads/e2e-pmcoil/PM COIL Molecule.brd+    was split at the first space - Fusion got ".../e2e-pmcoil/PM" and the open silently+    no-op'd, surfacing only as the generic "Fusion may not support this file" hint. A+    space-free copy of the same file opened instantly, which is what pinned it to path+    handling rather than file support.++    Two-step, so it works whichever way this Fusion build's parser behaves:+      1. QUOTE the path.+      2. If that fails and the path has spaces, retry with the Windows 8.3 SHORT path+         (GetShortPathNameW) - same file, no spaces, no copying.++    Returns (result, how) and raises the LAST exception if every attempt fails.+    """+    attempts = []+    quoted = '"%s"' % file_path.replace('"', '')+    attempts.append((quoted, "quoted"))+    if " " in file_path:+        try:+            import ctypes+            from ctypes import wintypes+            _gsp = ctypes.windll.kernel32.GetShortPathNameW+            _gsp.argtypes = [wintypes.LPCWSTR, wintypes.LPWSTR, wintypes.DWORD]+            _gsp.restype = wintypes.DWORD+            buf = ctypes.create_unicode_buffer(600)+            if _gsp(file_path, buf, 600) and buf.value and " " not in buf.value:+                attempts.append((buf.value, "shortpath"))+        except Exception:+            pass+    def _doc_name():+        try:+            d = app.activeDocument+            return d.name if d else None+        except Exception:+            return None++    before = _doc_name()+    last = None+    for arg, how in attempts:+        try:+            r = app.executeTextCommand("Document.newDesignFromLocal %s" % arg)+        except Exception as e:+            last = e+            continue+        # executeTextCommand does not always RAISE on failure - it can return an error+        # string and leave the document untouched. So confirm a document actually opened+        # before declaring victory, otherwise fall through to the next attempt.+        time.sleep(0.6)+        if _doc_name() != before:+            return r, how+        last = RuntimeError("open did not change the active document (result=%r)" % (r,))+    raise last if last else RuntimeError("no open attempt ran")+++def _open_electronics(app: adsk.core.Application, file_path: str, file_type: str, expected_ext: str) -> dict:+    """Common logic for opening an electronics file in Fusion."""+    if not file_path:+        return {+            "success": False,+            "error": f"No filePath specified. Provide a {expected_ext} file path.",+            "data": {+                "hint": f"Usage: fusion_open_{file_type.replace(' ', '_')} {{\"filePath\": \"C:/path/to/file{expected_ext}\"}}"+            },+        }++    file_path = file_path.replace("\\", "/")++    if not os.path.exists(file_path):+        return {+            "success": False,+            "error": f"File not found: {file_path}",+            "_hint": "The path may exist on Docker but not on the Windows host. Verify with desktop_list_directory on the host, or use push_file to copy from Docker first.",+            "data": {"filePath": file_path, "hint": "Check that the file path exists on the Windows desktop machine, not on Docker."},+        }++    ext = os.path.splitext(file_path)[1].lower()+    if ext != expected_ext:+        return {+            "success": False,+            "error": f"Expected a {expected_ext} file, got {ext}. Use the correct command for this file type.",+            "data": {+                "hint": {+                    ".sch": "Use fusion_open_schematic for .sch files",+                    ".brd": "Use fusion_open_board for .brd files",+                    ".lbr": "Use fusion_open_lbr for .lbr files",+                    ".step": "Use fusion_import_step for .step files",+                    ".stp": "Use fusion_import_step for .stp files",+                }.get(ext, f"This command only handles {expected_ext} files"),+            },+        }++    try:+        r, _open_how = _open_local_document(app, file_path)+    except Exception as e:+        return {+            "success": False,+            "error": f"Failed to open {file_type}: {e}",+            "_hint": "Call fusion_screenshot to check for a modal dialog blocking Fusion, then fusion_send_key escape to dismiss it, then retry.",+            "data": {+                "filePath": file_path,+                "hint": ("PATH WITH SPACES? This verb now quotes the path and falls back to the "+                         "Windows 8.3 short path, so spaces should work (issue #196). If it still "+                         "fails, verify the file EXISTS at exactly this path and is valid, then try "+                         "a space-free copy to isolate it. Otherwise Fusion may not support this "+                         "file, or it is not fully loaded/responsive."),+            },+        }++    time.sleep(1.0)++    # Get workspace info to confirm we landed in the right editor+    ws_info = {}+    try:+        active_ws = app.executeTextCommand("DebugCommands.ActiveWorkspace")+        ws_info["activeWorkspace"] = active_ws.strip() if active_ws else "unknown"+    except Exception:+        pass+    try:+        doc = app.activeDocument+        if doc:+            ws_info["activeDocument"] = doc.name+    except Exception:+        pass++    # Build helpful next-steps based on file type+    next_steps = {+        "schematic": [+            "Use fusion_electron_run to send EAGLE commands (e.g. WINDOW FIT, DISPLAY ALL)",+            "Use fusion_take_screenshot to capture the schematic view",+            "Use fusion_close_document to close without saving when done",+        ],+        "board layout": [+            "Use fusion_show_3d_board to switch to 3D PCB visualization",+            "Use fusion_electron_run to send EAGLE commands (e.g. WINDOW FIT, RATSNEST)",+            "Use fusion_take_screenshot to capture the board view",+            "Use fusion_close_document to close without saving when done",+        ],+    }++    return {+        "success": True,+        "output": f"Opened {file_type}: {os.path.basename(file_path)}",+        "message": f"Opened {file_type}: {os.path.basename(file_path)}. "+                   f"IMPORTANT: Fusion may show a blocking dialog that is NOT visible to the API. "+                   f"You MUST screenshot the Fusion window now to verify no dialog is blocking.",+        "data": {+            "filePath": file_path,+            "fileType": file_type,+            "nextSteps": next_steps.get(file_type, []),+            **ws_info,+        },+        "postOpenCheck": {+            "required": True,+            "steps": [+                "Run desktop_list_windows to find the Fusion HWND",+                "Run desktop_screenshot_window with that HWND",+                "If a dialog is visible, dismiss it with fusion_send_key {\"key\": \"escape\"} or fusion_click_fusion on the Cancel/X button",+                "Screenshot again to confirm the dialog is gone",+            ],+        },+    }+++def handle_open_schematic(app: adsk.core.Application, args: dict) -> dict:+    """Open a schematic (.sch) file in Fusion 360's Schematic Editor.++    PCB/ELECTRONICS NAV RULE: a board is NOT a standalone file - the schematic, 2D board and 3D board are VIEWS inside ONE electronics DESIGN. Open the DESIGN document first (fusion_open_cloud_file or fusion_open_by_urn), THEN switch to its schematic and its 2D board (fusion_show_2d_board) and 3D board (fusion_show_3d_board). A Select-Electronics-Design-File picker IS that design list of its schematic + board. An EMPTY 2D board usually means you opened a derivative or the wrong file, or it is out of sync - reopen the parent electronics DESIGN and switch to its board view; do NOT open a .brd or .sch as a standalone file.++    The schematic opens in the Electronics workspace where you can use+    EAGLE commands via fusion_electron_run (e.g. WINDOW FIT, DISPLAY ALL).++    Args:+        args: Dict with:+            - filePath: Path to the .sch file on the Windows desktop (required).+    """+    return _open_electronics(app, args.get("filePath", ""), "schematic", ".sch")+++def handle_open_board(app: adsk.core.Application, args: dict) -> dict:+    """Open a board layout (.brd) file in Fusion 360's Board Layout editor.++    PCB/ELECTRONICS NAV RULE: a board is NOT a standalone file - the schematic, 2D board and 3D board are VIEWS inside ONE electronics DESIGN. Open the DESIGN document first (fusion_open_cloud_file or fusion_open_by_urn), THEN switch to its schematic and its 2D board (fusion_show_2d_board) and 3D board (fusion_show_3d_board). A Select-Electronics-Design-File picker IS that design list of its schematic + board. An EMPTY 2D board usually means you opened a derivative or the wrong file, or it is out of sync - reopen the parent electronics DESIGN and switch to its board view; do NOT open a .brd or .sch as a standalone file.++    Opens the 2D board layout where you can see traces, pads, and components.+    Use fusion_show_3d_board to switch to the 3D PCB visualization.+    Use fusion_electron_run {"command": "BOARD"} to return to 2D.++    Args:+        args: Dict with:+            - filePath: Path to the .brd file on the Windows desktop (required).+    """+    return _open_electronics(app, args.get("filePath", ""), "board layout", ".brd")+++def handle_show_3d_board(app: adsk.core.Application, args: dict) -> dict:+    """Switch to the 3D PCB board view in Fusion 360.++    Must have a board (.brd) open in the Board Layout editor first.+    The board MUST have an outline on layer 20 (Dimension) — without it,+    Fusion cannot generate the 3D model.++    Uses the Fusion command Switch3dPcbDocCmd to switch workspaces.++    To return to 2D board layout, use:+        fusion_execute_text_command {"command": "Commands.Start Electron::Insert2DPCB"}+    """+    # Check current workspace+    ws = "unknown"+    try:+        ws = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+    except Exception:+        pass++    # Already in 3D PCB?+    if ws == "3D PCB":+        return {+            "success": True,+            "output": "Already in 3D PCB view.",+            "data": {+                "activeWorkspace": ws,+                "nextSteps": [+                    "Use fusion_take_screenshot to capture the 3D board view",+                    "Use fusion_show_2d_board to return to 2D layout",+                    "Use fusion_close_document to close without saving when done",+                ],+            },+        }++    # Must be in PCB Editor (board layout) to switch to 3D+    is_pcb_editor = False+    try:+        app.executeTextCommand("Electron.run DISPLAY")+        is_pcb_editor = True+    except Exception:+        pass++    if not is_pcb_editor:+        return {+            "success": False,+            "error": f"Not in Electronics editor (current workspace: {ws}). "+                     "Open a .brd board file first with fusion_open_board.",+            "_hint": "Call fusion_open_board {\"filePath\":\"...\"} to load a board, then retry fusion_show_3d_board.",+            "data": {+                "activeWorkspace": ws,+                "hint": "You need to open a .brd file first: fusion_open_board {\"filePath\": \"C:/path/to/board.brd\"}",+            },+        }++    # Switch to 3D PCB using Fusion's workspace switch command+    try:+        result = app.executeTextCommand("Commands.Start Switch3dPcbDocCmd")+    except Exception as e:+        err_msg = str(e)+        if "outline" in err_msg.lower() or "missing" in err_msg.lower():+            return {+                "success": False,+                "error": f"3D PCB failed: {e}. The board may be missing an outline on layer 20 (Dimension).",+                "_hint": "Call fusion_electron_run with a WIRE command on layer 20 to add a board outline, then retry fusion_show_3d_board.",+                "data": {+                    "hint": "Add a board outline on layer 20 (Dimension) using WIRE command, then try again.",+                },+            }+        return {+            "success": False,+            "error": f"Switch to 3D PCB failed: {e}",+            "data": {"activeWorkspace": ws},+        }++    time.sleep(2.0)++    # Zoom to fit in 3D view+    try:+        app.executeTextCommand("Commands.Start FitCommand")+    except Exception:+        pass  # FitCommand may report missing 3D models as an "error" but still works++    # Verify we're now in 3D PCB+    new_ws = "unknown"+    try:+        new_ws = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+    except Exception:+        pass++    if new_ws != "3D PCB":+        return {+            "success": False,+            "error": f"Switch to 3D PCB may have failed (workspace: {new_ws}). "+                     "Ensure the board has an outline on layer 20.",+            "_hint": "Call fusion_screenshot to check state, then verify the board has a layer-20 outline before retrying.",+            "data": {"activeWorkspace": new_ws},+        }++    return {+        "success": True,+        "output": "Switched to 3D PCB board view. Board outline, copper, solder mask, and component placeholders are shown in 3D.",+        "message": "Switched to 3D PCB view. IMPORTANT: Fusion may show a 'What to design?' or "+                   "'PCB out of date' dialog. You MUST screenshot the Fusion window to verify.",+        "data": {+            "activeWorkspace": new_ws,+            "nextSteps": [+                "FIRST: Screenshot Fusion window to check for blocking dialogs — dismiss with fusion_send_key escape",+                "Use fusion_take_screenshot to capture the 3D board view",+                "Use fusion_show_2d_board to return to 2D layout",+                "Use fusion_close_document to close without saving when done",+            ],+        },+        "postOpenCheck": {+            "required": True,+            "steps": [+                "Run desktop_list_windows to find the Fusion HWND",+                "Run desktop_screenshot_window with that HWND",+                "If a dialog is visible, dismiss it with fusion_send_key {\"key\": \"escape\"}",+                "Screenshot again to confirm the dialog is gone",+            ],+        },+    }+++def handle_import_electronics(app: adsk.core.Application, args: dict) -> dict:+    """Import a Fusion-native electronics file (.fsch/.fbrd/.flbr) as a new local project.++    These are Fusion 360's own electronics formats (not legacy EAGLE .sch/.brd).+    Uses Document.newDesignFromLocal to create a new document from the local file.++    After importing, use fusion_save_to_cloud to persist to the Fusion cloud.++    Args:+        args: Dict with:+            - filePath: Path to the .fsch, .fbrd, or .flbr file on Windows (required).+    """+    file_path = args.get("filePath", "")+    if not file_path:+        return {+            "success": False,+            "error": "No filePath specified. Provide a .fsch, .fbrd, or .flbr file path.",+            "data": {+                "hint": "Usage: fusion_import_electronics {\"filePath\": \"C:/path/to/file.fsch\"}",+                "supportedExtensions": [".fsch", ".fbrd", ".flbr"],+            },+        }++    file_path = file_path.replace("\\", "/")++    if not os.path.exists(file_path):+        return {+            "success": False,+            "error": f"File not found: {file_path}",+            "_hint": "The path may exist on Docker but not on the Windows host. Use push_file to copy it from Docker first, or verify the host-side path.",+            "data": {"filePath": file_path, "hint": "Check that the file path exists on the Windows desktop machine."},+        }++    ext = os.path.splitext(file_path)[1].lower()+    valid_extensions = {".fsch", ".fbrd", ".flbr"}+    if ext not in valid_extensions:+        ext_hints = {+            ".sch": "Use fusion_open_schematic for legacy EAGLE .sch files",+            ".brd": "Use fusion_open_board for legacy EAGLE .brd files",+            ".lbr": "Use fusion_open_lbr for legacy EAGLE .lbr files",+            ".step": "Use fusion_import_step for .step files",+            ".stp": "Use fusion_import_step for .stp files",+        }+        return {+            "success": False,+            "error": f"Unsupported extension '{ext}'. This command handles Fusion-native electronics formats: .fsch, .fbrd, .flbr",+            "_hint": ext_hints.get(ext, f"Supported: {', '.join(sorted(valid_extensions))}"),+            "data": {+                "hint": ext_hints.get(ext, f"Supported: {', '.join(sorted(valid_extensions))}"),+                "supportedExtensions": sorted(valid_extensions),+            },+        }++    file_type_map = {+        ".fsch": "Fusion schematic",+        ".fbrd": "Fusion board",+        ".flbr": "Fusion library",+    }+    file_type = file_type_map[ext]++    try:+        r, _open_how = _open_local_document(app, file_path)+    except Exception as e:+        return {+            "success": False,+            "error": f"Failed to import {file_type}: {e}",+            "data": {+                "filePath": file_path,+                "hint": "Fusion 360 may not support this file version. Ensure Fusion is fully loaded and responsive.",+            },+        }++    time.sleep(1.5)++    # Get workspace info to confirm we landed in the right editor+    ws_info = {}+    try:+        active_ws = app.executeTextCommand("DebugCommands.ActiveWorkspace")+        ws_info["activeWorkspace"] = active_ws.strip() if active_ws else "unknown"+    except Exception:+        pass+    try:+        doc = app.activeDocument+        if doc:+            ws_info["activeDocument"] = doc.name+    except Exception:+        pass++    next_steps = []+    if ext == ".fsch":+        next_steps = [+            "Use fusion_electron_run to send EAGLE commands (e.g. WINDOW FIT)",+            "Use fusion_save_to_cloud to persist this document to the Fusion cloud",+            "Use fusion_close_document to close without saving when done",+        ]+    elif ext == ".fbrd":+        next_steps = [+            "Use fusion_show_3d_board to switch to 3D PCB visualization",+            "Use fusion_electron_run to send EAGLE commands (e.g. WINDOW FIT, RATSNEST)",+            "Use fusion_save_to_cloud to persist this document to the Fusion cloud",+            "Use fusion_close_document to close without saving when done",+        ]+    elif ext == ".flbr":+        next_steps = [+            "Use fusion_export_lbr to verify library contents (.scr text format)",+            "Use fusion_save_to_cloud to persist this library to the Fusion cloud",+            "Use fusion_close_document to close without saving when done",+        ]++    return {+        "success": True,+        "output": f"Imported {file_type}: {os.path.basename(file_path)}",+        "message": f"Imported {file_type}: {os.path.basename(file_path)}. "+                   f"This is a NEW local document — use fusion_save_to_cloud to persist it. "+                   f"IMPORTANT: Fusion may show a blocking dialog. Screenshot to verify.",+        "data": {+            "filePath": file_path,+            "fileType": file_type,+            "extension": ext,+            "nextSteps": next_steps,+            **ws_info,+        },+        "postOpenCheck": {+            "required": True,+            "steps": [+                "Run desktop_list_windows to find the Fusion HWND",+                "Run desktop_screenshot_window with that HWND",+                "If a dialog is visible, dismiss it with fusion_send_key {\"key\": \"escape\"}",+                "Screenshot again to confirm the dialog is gone",+            ],+        },+    }+++def handle_show_2d_board(app: adsk.core.Application, args: dict) -> dict:+    """Switch back to the 2D board layout from 3D PCB view.++    Uses the Fusion command Electron::Insert2DPCB to return to PCB Editor.+    """+    ws = "unknown"+    try:+        ws = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+    except Exception:+        pass++    if ws == "PCB Editor":+        return {+            "success": True,+            "output": "Already in 2D board layout.",+            "data": {"activeWorkspace": ws},+        }++    try:+        app.executeTextCommand("Commands.Start SwitchPcbDocCmd")+    except Exception as e:+        return {+            "success": False,+            "error": f"Switch to 2D board failed: {e}",+            "_hint": "Call fusion_open_board {\"filePath\":\"...\"} to ensure a board is loaded, then retry.",+            "data": {"activeWorkspace": ws},+        }++    time.sleep(1.0)++    new_ws = "unknown"+    try:+        new_ws = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+    except Exception:+        pass++    return {+        "success": True,+        "output": "Switched to 2D board layout. EAGLE commands via fusion_electron_run will work.",+        "data": {+            "activeWorkspace": new_ws,+            "nextSteps": [+                "Use fusion_electron_run to send EAGLE commands",+                "Use fusion_show_3d_board to switch back to 3D view",+            ],+        },+    }+++def handle_show_schematic(app: adsk.core.Application, args: dict) -> dict:+    """Switch the OPEN electronics design to its SCHEMATIC view.++    The schematic / 2D board / 3D board are VIEWS of ONE electronics design - open the+    PROJECT first (fusion_open_cloud_file / fusion_open_by_urn), then switch views with+    fusion_show_schematic / fusion_show_2d_board / fusion_show_3d_board. Uses Fusion's+    SwitchSchDocCmd (the symmetric partner of SwitchPcbDocCmd / Switch3dPcbDocCmd).+    Drive the schematic for demos with fusion_electron_zoom / _pan / _select.+    """+    ws = "unknown"+    try:+        ws = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+    except Exception:+        pass++    # Already viewing the schematic?+    cur_pt = ""+    try:+        cur_pt = app.activeProduct.productType+    except Exception:+        pass+    if cur_pt == "SchematicProductType":+        return {+            "success": True,+            "output": "Already in the schematic view.",+            "data": {"activeWorkspace": ws, "productType": cur_pt},+        }++    try:+        app.executeTextCommand("Commands.Start SwitchSchDocCmd")+    except Exception as e:+        return {+            "success": False,+            "error": f"Switch to schematic failed: {e}",+            "_hint": "Open the electronics DESIGN first (fusion_open_cloud_file / fusion_open_by_urn), "+                     "then retry. The schematic is a VIEW of the design, not a standalone file.",+            "data": {"activeWorkspace": ws},+        }++    time.sleep(1.2)+    try:+        app.executeTextCommand("Electron.run WINDOW FIT")+    except Exception:+        pass++    new_ws = "unknown"+    new_pt = ""+    try:+        new_ws = app.executeTextCommand("DebugCommands.ActiveWorkspace").strip()+    except Exception:+        pass+    try:+        new_pt = app.activeProduct.productType+    except Exception:+        pass++    return {+        "success": True,+        "output": "Switched to the schematic view. Drive it with fusion_electron_zoom / _pan / _select "+                  "or fusion_electron_run WINDOW commands.",+        "message": "Switched to the schematic. Fusion may show a blocking dialog that is NOT visible to "+                   "the API - screenshot the Fusion window to verify.",+        "data": {+            "activeWorkspace": new_ws,+            "productType": new_pt,+            "nextSteps": [+                "fusion_electron_zoom / fusion_electron_pan to move the view for a recording",+                "fusion_show_2d_board / fusion_show_3d_board to switch to the board / 3D",+                "fusion_take_screenshot to capture the schematic",+            ],+        },+        "postOpenCheck": {+            "required": True,+            "steps": [+                "Run desktop_screenshot_window on the Fusion HWND",+                "If a dialog is visible, dismiss it with fusion_send_key {\"key\": \"escape\"}",+            ],+        },+    }
addin/AdomBridge/commands/open_lbr.pyadded+186
@@ -0,0 +1,186 @@+"""Open an EAGLE .lbr library file in Fusion 360's Electronics workspace.++Uses the Document.newDesignFromLocal text command to open the file, which+switches Fusion to the Electronics Library editor automatically.+This avoids the fragile workspace-switching dance.++Note: Document.Open fails with error 3 for .lbr files, but+Document.newDesignFromLocal works reliably.++Flow:+  1. Write .lbr XML file to disk (caller provides path or XML content)+  2. Document.newDesignFromLocal <path> opens it in Electronics Library editor+  3. Optionally navigate to a specific symbol with Electron.run EDIT <name>.sym+  4. Optionally export via EXPORT SCRIPT for round-trip verification+"""++import adsk.core+import os+import tempfile+import time+++def handle_open_lbr(app: adsk.core.Application, args: dict) -> dict:+    """Open an EAGLE .lbr file in the Electronics Library editor.++    Args:+        args: Dict with:+            - filePath: Path to the .lbr file on disk (required).+            - symbolName: Optional symbol name to navigate to after opening.+            - verify: If True, exports the library back via EXPORT SCRIPT.+    """+    file_path = args.get("filePath", "")+    symbol_name = args.get("symbolName", "")+    verify = args.get("verify", False)++    if not file_path:+        return {"success": False, "error": "No filePath specified"}++    # Normalize path for Fusion (forward slashes)+    file_path = file_path.replace("\\", "/")++    if not os.path.exists(file_path):+        return {+            "success": False,+            "error": f"File not found: {file_path}",+            "_hint": "The path may exist on Docker but not on the Windows host. Use push_file to copy from Docker, or verify the host-side path.",+        }++    if not file_path.lower().endswith(".lbr"):+        return {+            "success": False,+            "error": f"Not a .lbr file: {file_path}",+            "_hint": "Use fusion_open_schematic for .sch files, fusion_open_board for .brd files, or fusion_import_electronics for .fsch/.fbrd/.flbr files.",+        }++    results = []++    # Step 1: Open the .lbr file via Document.newDesignFromLocal+    # (Document.Open fails with error 3 for .lbr files)+    try:+        # issue #196: quote + 8.3 fallback so paths WITH SPACES open (executeTextCommand+        # is space-delimited, so an unquoted path was silently truncated at the space).+        from .open_electronics_file import _open_local_document+        r, _open_how = _open_local_document(app, file_path)+        results.append(f"Document.newDesignFromLocal: {r if r else 'ok'}")+    except Exception as e:+        return {+            "success": False,+            "error": f"Document.newDesignFromLocal failed: {e}",+            "_hint": "Call fusion_screenshot to check for a modal dialog blocking Fusion, dismiss with fusion_send_key escape, then retry.",+            "data": {"filePath": file_path},+        }++    # Step 2: If a symbol name was given, navigate to it+    if symbol_name:+        # Give Fusion a moment to finish opening the library+        time.sleep(1)++        sym_ref = symbol_name if symbol_name.endswith(".sym") else f"{symbol_name}.sym"+        try:+            app.executeTextCommand(f"Electron.run EDIT {sym_ref}")+            results.append(f"EDIT {sym_ref}: ok")+        except Exception as e:+            results.append(f"EDIT {sym_ref} failed: {e}")++        # Zoom to fit+        try:+            app.executeTextCommand("Electron.run WINDOW FIT")+            results.append("WINDOW FIT: ok")+        except Exception:+            pass++    # Step 3: Verification via EXPORT SCRIPT+    verification = None+    if verify:+        verification = _export_and_verify(app, symbol_name)+        results.append(f"Verification: exported={verification.get('exported', False)}")++    response = {+        "success": True,+        "output": f"Opened library: {os.path.basename(file_path)}",+        "data": {"results": results, "filePath": file_path},+    }+    if symbol_name:+        response["data"]["symbolName"] = symbol_name+    if verification:+        response["data"]["verification"] = verification+    return response+++def handle_export_lbr(app: adsk.core.Application, args: dict) -> dict:+    """Export the current Electronics library via EXPORT SCRIPT.++    This exports the library contents to an EAGLE .scr script file,+    which is a text representation of the entire library. Useful for+    verifying that a library was loaded correctly (round-trip test).++    Args:+        args: Dict with:+            - outputPath: Path to write the .scr export (optional,+                         defaults to a temp file).+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        import uuid+        output_path = os.path.join(tempfile.gettempdir(), f"_adom_export_{uuid.uuid4().hex[:8]}.scr")++    output_path = output_path.replace("\\", "/")++    try:+        app.executeTextCommand(f"Electron.run EXPORT SCRIPT '{output_path}'")+    except Exception as e:+        return {+            "success": False,+            "error": f"EXPORT SCRIPT failed: {e}. "+                     "Ensure you are in an Electronics editor (library, schematic, or board).",+            "_hint": "Call fusion_open_lbr {\"filePath\":\"...\"} to enter the Electronics Library editor, then retry.",+        }++    if not os.path.exists(output_path):+        return {+            "success": False,+            "error": f"Export file was not created at {output_path}",+        }++    size = os.path.getsize(output_path)+    # Read a preview of the exported content+    with open(output_path, "r", errors="replace") as f:+        preview = f.read(2000)++    return {+        "success": True,+        "output": f"Exported library to {output_path} ({size} bytes)",+        "data": {+            "outputPath": output_path,+            "fileSize": size,+            "preview": preview,+        },+    }+++def _export_and_verify(app: adsk.core.Application, symbol_name: str = "") -> dict:+    """Export library and check if the symbol exists in the output."""+    import uuid+    verify_path = os.path.join(tempfile.gettempdir(), f"_adom_verify_{uuid.uuid4().hex[:8]}.scr")+    try:+        app.executeTextCommand(f"Electron.run EXPORT SCRIPT '{verify_path}'")+        if os.path.exists(verify_path):+            with open(verify_path, "r", errors="replace") as f:+                content = f.read()+            result = {+                "exported": True,+                "fileSize": os.path.getsize(verify_path),+                "preview": content[:1000],+            }+            if symbol_name:+                # EAGLE uppercases symbol names in EXPORT SCRIPT output+                has_symbol = (+                    f"Edit '{symbol_name.upper()}.sym'" in content+                    or f"Edit '{symbol_name}.sym'" in content+                )+                result["hasSymbol"] = has_symbol+            return result+        return {"exported": False, "error": "Export file not created"}+    except Exception as e:+        return {"exported": False, "error": str(e)}
addin/AdomBridge/commands/parameters.pyadded+144
@@ -0,0 +1,144 @@+"""Parameter commands — get and set design parameters."""++import adsk.core+import adsk.fusion+++def handle_get_parameters(app: adsk.core.Application, args: dict) -> dict:+    """Get all parameters (user + model) from the active design.++    Args:+        args: Optional dict with:+            - type: "user", "model", or "all" (default: "all").+    """+    product = app.activeProduct+    if not product or product.productType != "DesignProductType":+        return {+            "success": False,+            "error": "No active design open in Fusion 360",+            "_hint": "Call fusion_open_cloud_file to open a Design document, then retry.",+        }++    design = adsk.fusion.Design.cast(product)+    param_type = args.get("type", "all").lower()++    result = []++    def _safe(fn):+        # Parameter.value THROWS "Parameter is not numeric type" for string/text+        # parameters (caught live 2026-07-06: get_parameters blew up the whole call on+        # one non-numeric param). Read every field defensively so one odd parameter+        # never kills the enumeration.+        try:+            return fn()+        except Exception:+            return None++    if param_type in ("user", "all"):+        for i in range(design.userParameters.count):+            p = design.userParameters.item(i)+            result.append({+                "name": _safe(lambda: p.name),+                "type": "user",+                "expression": _safe(lambda: p.expression),+                "value": _safe(lambda: p.value),+                "unit": _safe(lambda: p.unit),+                "comment": _safe(lambda: p.comment),+            })++    if param_type in ("model", "all"):+        for i in range(design.allParameters.count):+            p = design.allParameters.item(i)+            # Skip user params if we already included them+            if param_type == "all" and _is_user_param(design, p.name):+                continue+            result.append({+                "name": _safe(lambda: p.name),+                "type": "model",+                "expression": _safe(lambda: p.expression),+                "value": _safe(lambda: p.value),+                "unit": _safe(lambda: p.unit),+            })++    return {+        "success": True,+        "data": result,+        "output": f"Found {len(result)} parameter(s).",+    }+++def handle_set_parameter(app: adsk.core.Application, args: dict) -> dict:+    """Set a parameter's expression by name.++    Args:+        args: Dict with:+            - name: Parameter name (required).+            - expression: New expression string (required), e.g. "10 mm".+    """+    name = args.get("name", "")+    expression = args.get("expression", "")+    if not name:+        return {"success": False, "error": "No parameter name specified"}+    if not expression:+        return {"success": False, "error": "No expression specified"}++    product = app.activeProduct+    if not product or product.productType != "DesignProductType":+        return {+            "success": False,+            "error": "No active design open in Fusion 360",+            "_hint": "Call fusion_open_cloud_file to open a Design document, then retry.",+        }++    design = adsk.fusion.Design.cast(product)++    # Try user parameters first, then all parameters+    param = None+    for i in range(design.userParameters.count):+        p = design.userParameters.item(i)+        if p.name == name:+            param = p+            break++    if not param:+        for i in range(design.allParameters.count):+            p = design.allParameters.item(i)+            if p.name == name:+                param = p+                break++    if not param:+        return {+            "success": False,+            "error": f"Parameter not found: {name}",+            "_hint": "Call fusion_get_parameters to list all valid parameter names, then retry with a correct name.",+        }++    old_expr = param.expression+    try:+        param.expression = expression+    except Exception as e:+        return {+            "success": False,+            "error": f"Failed to set parameter: {e}",+            "_hint": "Verify the expression format (e.g., \"10 mm\", \"5 deg\") and that units match the parameter's unit type.",+        }++    return {+        "success": True,+        "output": f"Parameter '{name}' changed: {old_expr} -> {expression}",+        "data": {+            "name": param.name,+            "expression": param.expression,+            "value": param.value,+            "unit": param.unit,+        },+    }+++def _is_user_param(design: adsk.fusion.Design, name: str) -> bool:+    """Check if a parameter name exists in the user parameters."""+    for i in range(design.userParameters.count):+        if design.userParameters.item(i).name == name:+            return True+    return False
addin/AdomBridge/commands/physical_properties.pyadded+64
@@ -0,0 +1,64 @@+"""Per-component physical properties (volume, mass, density, area, center of mass).++Fusion exposes physical properties only through the modeling API, so before this verb a+caller had to run getPhysicalProperties inside fusion_run_modeling_script. This verb reads+them directly, per component, so BOM/costing tools can price by volume or mass without a+custom script.+"""++import adsk.core+import adsk.fusion++_ACC = {+    "low": adsk.fusion.CalculationAccuracy.LowCalculationAccuracy,+    "medium": adsk.fusion.CalculationAccuracy.MediumCalculationAccuracy,+    "high": adsk.fusion.CalculationAccuracy.HighCalculationAccuracy,+    "veryhigh": adsk.fusion.CalculationAccuracy.VeryHighCalculationAccuracy,+}+++def handle_physical_properties(app: adsk.core.Application, args: dict) -> dict:+    """Return physical properties per unique component in the active design.++    args:+      names      optional list of component names to measure (default: all).+      accuracy   optional "low" | "medium" | "high" | "veryhigh" (default: low).+    """+    design = adsk.fusion.Design.cast(app.activeProduct)+    if not design:+        return {"success": False, "error": "No active Fusion Design.",+                "_hint": "Open a design in the Design workspace, then retry."}++    args = args or {}+    names = set(args.get("names") or [])+    acc = _ACC.get((args.get("accuracy") or "low").lower(),+                   adsk.fusion.CalculationAccuracy.LowCalculationAccuracy)++    out = {}+    seen = set()+    for occ in design.rootComponent.allOccurrences:+        comp = occ.component+        if comp.name in seen:+            continue+        if names and comp.name not in names:+            continue+        seen.add(comp.name)+        try:+            pp = comp.getPhysicalProperties(acc)+            entry = {+                "volume_cm3": round(pp.volume, 4),+                "mass_kg": round(pp.mass, 6),+                "density": round(pp.density, 6),+                "area_cm2": round(pp.area, 4),+            }+            try:+                com = pp.centerOfMass+                entry["center_of_mass"] = [round(com.x, 4), round(com.y, 4), round(com.z, 4)]+            except Exception:+                pass+            out[comp.name] = entry+        except Exception as e:+            out[comp.name] = {"error": str(e)[:80]}++    return {"success": True, "count": len(out), "accuracy": (args.get("accuracy") or "low"),+            "properties": out}
addin/AdomBridge/commands/screenshot.pyadded+136
@@ -0,0 +1,136 @@+"""Screenshot command — capture the Fusion 360 viewport."""++import adsk.core+import os+import time+from pathlib import Path+++def _build_view_orientations():+    """Build orientation map at runtime to avoid crashing if enum values differ."""+    orientations = {"home": None}+    try:+        vo = adsk.core.ViewOrientations+        mapping = {+            "front": "FrontViewOrientation",+            "back": "BackViewOrientation",+            "top": "TopViewOrientation",+            "bottom": "BottomViewOrientation",+            "left": "LeftViewOrientation",+            "right": "RightViewOrientation",+            "iso_top_front_right": "IsoTopFrontRightViewOrientation",+            "iso_top_front_left": "IsoTopFrontLeftViewOrientation",+            "iso_top_back_right": "IsoTopBackRightViewOrientation",+            "iso_top_back_left": "IsoTopBackLeftViewOrientation",+            "iso_bottom_front_right": "IsoBottomFrontRightViewOrientation",+            "iso_bottom_front_left": "IsoBottomFrontLeftViewOrientation",+            "iso_bottom_back_right": "IsoBottomBackRightViewOrientation",+            "iso_bottom_back_left": "IsoBottomBackLeftViewOrientation",+        }+        for name, attr in mapping.items():+            if hasattr(vo, attr):+                orientations[name] = getattr(vo, attr)+    except Exception:+        pass+    return orientations+++def handle_take_screenshot(app: adsk.core.Application, args: dict) -> dict:+    """Capture the active viewport to a PNG file.++    Uses Fusion's viewport render API (same as Capture Image from the menu)+    for high-quality renders at any resolution, without opening a dialog.++    Args:+        args: Dict with:+            - outputPath: Full path for the output .png file (required).+            - width: Image width in pixels (default: 1920).+            - height: Image height in pixels (default: 1080).+            - orientation: Camera orientation preset (optional).+              One of: "home", "front", "back", "top", "bottom", "left", "right",+              "iso_top_front_right", "iso_top_front_left", etc.+            - fitToView: If true, zoom to fit all geometry (default: true).+            - listOrientations: If true, return available orientations.+    """+    VIEW_ORIENTATIONS = _build_view_orientations()++    # List orientations mode+    if args.get("listOrientations", False):+        return {+            "success": True,+            "output": f"{len(VIEW_ORIENTATIONS)} view orientations available",+            "data": {"orientations": list(VIEW_ORIENTATIONS.keys())},+        }++    output_path = args.get("outputPath", "")+    if not output_path:+        return {"success": False, "error": "No outputPath specified"}++    width = int(args.get("width", 1920))+    height = int(args.get("height", 1080))+    orientation = args.get("orientation", "").lower().strip()+    fit_to_view = args.get("fitToView", True)++    viewport = app.activeViewport+    if not viewport:+        return {+            "success": False,+            "error": "No active viewport",+            "_hint": "Call fusion_open_cloud_file or fusion_open_board to open a document first — there is nothing to screenshot.",+        }++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    # Set camera orientation if specified+    orientation_applied = None+    if orientation:+        if orientation not in VIEW_ORIENTATIONS:+            return {+                "success": False,+                "error": f"Unknown orientation '{orientation}'. "+                         f"Available: {', '.join(VIEW_ORIENTATIONS.keys())}",+            }++        camera = viewport.camera+        view_enum = VIEW_ORIENTATIONS[orientation]++        if view_enum is not None:+            camera.viewOrientation = view_enum+        camera.isFitView = True if fit_to_view else False+        viewport.camera = camera++        # Let Fusion render the new view+        adsk.doEvents()+        time.sleep(0.3)+        adsk.doEvents()++        orientation_applied = orientation+    elif fit_to_view:+        camera = viewport.camera+        camera.isFitView = True+        viewport.camera = camera+        adsk.doEvents()++    result = viewport.saveAsImageFile(output_path, width, height)++    if result:+        size = os.path.getsize(output_path) if os.path.exists(output_path) else 0+        response = {+            "success": True,+            "output": f"Screenshot saved to {output_path} ({width}x{height})",+            "data": {+                "outputPath": output_path,+                "width": width,+                "height": height,+                "fileSizeKB": size // 1024,+            },+        }+        if orientation_applied:+            response["data"]["orientation"] = orientation_applied+        return response++    return {+        "success": False,+        "error": "Screenshot capture failed",+        "_hint": "Try desktop_screenshot_window with the Fusion HWND as a fallback (captures the full window including UI chrome).",+    }
addin/AdomBridge/commands/silkscreen_capture.pyadded+308
@@ -0,0 +1,308 @@+"""Silkscreen capture — render isolated top/bottom silkscreen layer PNGs.++Hides all 3D bodies except the target silkscreen layer, aims the camera+at the PCB bounding box, captures a 2048x2048 transparent-background PNG,+then restores the original visibility and camera state.++This is a low-level primitive. Orchestration (which documents to open,+which workspace to activate, where to save) belongs in the skill layer.+"""++import adsk.core+import adsk.fusion+import os+import time+from pathlib import Path+++def _pump_events(iterations=5):+    """Flush Fusion's event queue so visibility/camera changes render."""+    try:+        for _ in range(iterations):+            adsk.doEvents()+    except Exception:+        pass+++def _compute_pcb_bbox(design):+    """Union bounding boxes of all bodies to frame the board."""+    combined = None++    def merge(bbox):+        nonlocal combined+        if not bbox:+            return+        if combined is None:+            combined = adsk.core.BoundingBox3D.create(+                bbox.minPoint.copy(), bbox.maxPoint.copy()+            )+        else:+            combined.expand(bbox.minPoint)+            combined.expand(bbox.maxPoint)++    for ci in range(design.allComponents.count):+        comp = design.allComponents.item(ci)+        for bi in range(comp.bRepBodies.count):+            try:+                merge(comp.bRepBodies.item(bi).boundingBox)+            except Exception:+                pass+        for mi in range(comp.meshBodies.count):+            try:+                merge(comp.meshBodies.item(mi).boundingBox)+            except Exception:+                pass+    return combined+++def _bbox_center_and_extent(bbox):+    if bbox is None:+        return adsk.core.Point3D.create(0, 0, 0), 20.0, 20.0+    mn, mx = bbox.minPoint, bbox.maxPoint+    cx = (mn.x + mx.x) / 2+    cy = (mn.y + mx.y) / 2+    cz = (mn.z + mx.z) / 2+    xy_ext = max(abs(mx.x - mn.x), abs(mx.y - mn.y), 1.0)+    z_ext = max(abs(mx.z - mn.z), 1.0)+    return adsk.core.Point3D.create(cx, cy, cz), xy_ext, z_ext+++def _is_silk_match(name, target):+    """True if body/mesh/canvas name matches the target silkscreen layer."""+    n = name.lower()+    return "silk" in n and target in n+++def _store_visibility(design):+    """Snapshot visibility of all bodies, meshes, and canvases."""+    state = {"root_b": {}, "root_m": {}, "comps": {}}+    root = design.rootComponent+    for i in range(root.bRepBodies.count):+        state["root_b"][i] = root.bRepBodies.item(i).isVisible+    for i in range(root.meshBodies.count):+        state["root_m"][i] = root.meshBodies.item(i).isVisible+    for ci in range(design.allComponents.count):+        comp = design.allComponents.item(ci)+        ck = ci+        state["comps"][ck] = {"b": {}, "m": {}, "cv": {}}+        for bi in range(comp.bRepBodies.count):+            state["comps"][ck]["b"][bi] = comp.bRepBodies.item(bi).isVisible+        for mi in range(comp.meshBodies.count):+            state["comps"][ck]["m"][mi] = comp.meshBodies.item(mi).isVisible+        for cvi in range(comp.canvases.count):+            try:+                c = comp.canvases.item(cvi)+                state["comps"][ck]["cv"][cvi] = getattr(c, "isLightBulbOn", True)+            except Exception:+                pass+    return state+++def _restore_visibility(design, state):+    """Restore a previous visibility snapshot."""+    if not state:+        return+    root = design.rootComponent+    for i, vis in state.get("root_b", {}).items():+        try:+            root.bRepBodies.item(i).isVisible = vis+        except Exception:+            pass+    for i, vis in state.get("root_m", {}).items():+        try:+            root.meshBodies.item(i).isVisible = vis+        except Exception:+            pass+    for ci in range(design.allComponents.count):+        cs = state.get("comps", {}).get(ci, {})+        comp = design.allComponents.item(ci)+        for bi, vis in cs.get("b", {}).items():+            try:+                comp.bRepBodies.item(bi).isVisible = vis+            except Exception:+                pass+        for mi, vis in cs.get("m", {}).items():+            try:+                comp.meshBodies.item(mi).isVisible = vis+            except Exception:+                pass+        for cvi, vis in cs.get("cv", {}).items():+            try:+                c = comp.canvases.item(cvi)+                if hasattr(c, "isLightBulbOn"):+                    c.isLightBulbOn = vis+            except Exception:+                pass+++def _hide_all_except_silk(design, target):+    """Hide everything except the target silkscreen layer ('top'/'bottom').++    Silkscreen in Fusion 3D PCB is stored as Canvases (not bodies).+    Canvases are overlaid on the Board body, so the Board body must stay+    visible as a backdrop — otherwise the canvas renders over nothing and+    the viewport capture comes out blank.+    """+    root = design.rootComponent++    for i in range(root.bRepBodies.count):+        b = root.bRepBodies.item(i)+        b.isVisible = False+    for i in range(root.meshBodies.count):+        m = root.meshBodies.item(i)+        m.isVisible = False++    for ci in range(design.allComponents.count):+        comp = design.allComponents.item(ci)+        comp_name = comp.name.lower()++        for bi in range(comp.bRepBodies.count):+            b = comp.bRepBodies.item(bi)+            # Keep the Board body visible — canvases need it as a backdrop+            if comp_name == "board" and b.name.lower() == "board":+                b.isVisible = True+            else:+                b.isVisible = False++        for mi in range(comp.meshBodies.count):+            m = comp.meshBodies.item(mi)+            m.isVisible = False++        for cvi in range(comp.canvases.count):+            c = comp.canvases.item(cvi)+            try:+                if hasattr(c, "isLightBulbOn"):+                    c.isLightBulbOn = _is_silk_match(c.name, target)+            except Exception:+                pass+++def _capture_png(viewport, output_path, width=2048, height=2048):+    """Save viewport as PNG, preferring transparent background."""+    try:+        opts = adsk.core.SaveImageFileOptions.create(output_path)+        opts.width = width+        opts.height = height+        opts.isBackgroundTransparent = True+        opts.isAntiAliased = True+        if viewport.saveAsImageFileWithOptions(opts):+            return True+    except Exception:+        pass+    try:+        return viewport.saveAsImageFile(output_path, width, height)+    except Exception:+        return False+++# ── Public handler ──────────────────────────────────────────────────────++def handle_take_silkscreen_screenshot(app: adsk.core.Application, args: dict) -> dict:+    """Capture an isolated silkscreen layer as a transparent-background PNG.++    Requires the active document to be a 3D Design (not PCB Editor).+    Call fusion_show_3d_board first if you're in the 2D board view.++    Args:+        outputPath (str): Full path for the output .png file (required).+        layer (str): "top" or "bottom" (required).+        width (int): Image width in pixels (default: 2048).+        height (int): Image height in pixels (default: 2048).++    Returns success + outputPath + fileSizeKB.+    """+    output_path = args.get("outputPath", "")+    if not output_path:+        return {+            "success": False,+            "error": "outputPath is required",+            "_hint": 'Provide {"outputPath": "C:/tmp/silk_top.png", "layer": "top"}',+        }++    layer = args.get("layer", "").lower().strip()+    if layer not in ("top", "bottom"):+        return {+            "success": False,+            "error": f"layer must be 'top' or 'bottom', got '{layer}'",+            "_hint": '{"outputPath": "...", "layer": "top"}',+        }++    width = int(args.get("width", 2048))+    height = int(args.get("height", 2048))++    # Need an active Design product (3D view)+    product = app.activeProduct+    if not product or product.productType != "DesignProductType":+        return {+            "success": False,+            "error": "No active Design document. Silkscreen capture requires the 3D PCB view.",+            "_hint": "Call fusion_show_3d_board to switch to the 3D view, then retry.",+        }+    design = adsk.fusion.Design.cast(product)++    viewport = app.activeViewport+    if not viewport:+        return {"success": False, "error": "No active viewport"}++    Path(output_path).parent.mkdir(parents=True, exist_ok=True)++    # Save state+    camera = viewport.camera+    orig_eye = camera.eye.copy()+    orig_target = camera.target.copy()+    orig_up = camera.upVector.copy()+    bbox = _compute_pcb_bbox(design)+    vis_state = _store_visibility(design)++    try:+        center, xy_ext, z_ext = _bbox_center_and_extent(bbox)++        # Hide everything except the target silkscreen layer+        _hide_all_except_silk(design, layer)++        # Aim camera straight down (top) or straight up (bottom)+        if layer == "top":+            eye_z = center.z + z_ext + xy_ext * 2.0+        else:+            eye_z = center.z - z_ext - xy_ext * 2.0++        camera.eye = adsk.core.Point3D.create(center.x, center.y, eye_z)+        camera.target = adsk.core.Point3D.create(center.x, center.y, center.z)+        camera.upVector = adsk.core.Vector3D.create(0, 1, 0)+        camera.viewExtents = xy_ext * 1.2+        camera.isSmoothTransition = False+        viewport.camera = camera+        viewport.refresh()++        # Let GPU finish rendering the new visibility state+        _pump_events()+        time.sleep(1.0)++        ok = _capture_png(viewport, output_path, width, height)+        if not ok:+            return {+                "success": False,+                "error": "Viewport capture failed",+                "_hint": "Try desktop_screenshot_window as a fallback.",+            }++        size = os.path.getsize(output_path) if os.path.exists(output_path) else 0+        return {+            "success": True,+            "output": f"Silkscreen {layer} captured to {output_path}",+            "data": {+                "outputPath": output_path.replace("\\", "/"),+                "layer": layer,+                "width": width,+                "height": height,+                "fileSizeKB": round(size / 1024, 1),+            },+        }+    finally:+        # Always restore+        camera.eye = orig_eye+        camera.target = orig_target+        camera.upVector = orig_up+        viewport.camera = camera+        viewport.refresh()+        _restore_visibility(design, vis_state)
addin/AdomBridge/http_server.pyadded+479
@@ -0,0 +1,479 @@+"""Background HTTP server for the Adom Bridge add-in.++Runs on a daemon thread inside Fusion 360's process.+Incoming POST /command requests fire a CustomEvent to marshal execution+to the main Fusion thread, then wait for the result.++Threading model:+    - HTTP server is ThreadingHTTPServer: multiple HTTP threads can serve+      requests concurrently (for /health, status, etc.).+    - Fusion's main thread is a HARD SINGLETON. All Fusion API work is+      marshaled via CustomEvent and executed serially there.+    - A module-level _main_thread_lock serializes CustomEvent fires so that+      only one request has work pending on the main thread at any time.+      New HTTP threads block on the lock until the in-flight request+      completes. This prevents request stacking (which wastes main-thread+      cycles on exports whose HTTP waiter already gave up).+    - A staleness check in set_result() drops results whose HTTP waiter has+      already timed out. The CustomEventHandler also checks staleness+      BEFORE dispatching, so it can skip heavy work entirely.+"""++import json+import os+import socket+import threading+import time+import urllib.request+import uuid+from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler++import adsk.core++from .commands.cloud_documents import get_walk_progress++PORT = 8774++# Add-in version — read from the sibling manifest so /health + /status can+# REPORT it. The bridge compares this against the version it bundles to catch a+# STALE add-in (issue #55: an old Roaming add-in that never re-synced from the+# bridge cache, which made fusion_aps_open fail SILENTLY). Sourced from the+# manifest so a single bump is the source of truth (no hardcode to drift).+def _read_addin_version():+    try:+        mf = os.path.join(os.path.dirname(__file__), "AdomBridge.manifest")+        with open(mf, "r", encoding="utf-8") as f:+            return (json.load(f) or {}).get("version", "unknown")+    except Exception:+        return "unknown"++ADDIN_VERSION = _read_addin_version()++_server = None+_server_thread = None+_custom_event_id = None+_app = None++# Thread-safe result passing: request_id -> (Event, result_dict)+_result_events = {}+_result_data = {}+_lock = threading.Lock()++# Main thread singleton lock — only ONE request may have a CustomEvent+# in flight to Fusion's main thread at any time. HTTP threads block+# here to prevent request stacking.+_main_thread_lock = threading.Lock()++# Main thread liveness tracking+_last_main_thread_ts = 0.0  # time.time() of last successful set_result()+_pending_request_ids = set()  # request_ids currently waiting for main thread++# Busy state tracking — which command currently holds the main thread lock.+# Read by the /status endpoint (non-blocking) so ANY bridge can check if+# the add-in is busy, even cross-process. This is the single source of truth.+_busy_state_lock = threading.Lock()+_busy_state = None  # None or {"command": str, "started_at": float, "request_id": str}+++def _set_busy(command: str, request_id: str):+    with _busy_state_lock:+        global _busy_state+        _busy_state = {"command": command, "started_at": time.time(), "request_id": request_id}+++def _clear_busy():+    with _busy_state_lock:+        global _busy_state+        _busy_state = None+++def _get_busy() -> dict | None:+    with _busy_state_lock:+        return dict(_busy_state) if _busy_state else None+++# ── Stale-lock watchdog (v1.0.2) ──────────────────────────────────────+#+# Failure mode being defended against:+#   Fusion's native cloud SDK can wedge on a slow / failed cloud API call+#   while holding the Python GIL. While wedged, Python code in the addin+#   does NOT run — including the per-command timeout in _wait_for_result.+#   The HTTP thread eventually times out (after `timeout` seconds) and+#   returns to the client, but the `finally` block can't run because the+#   thread is blocked at the C++/Fusion boundary. Net result:+#     - _main_thread_lock stays held forever+#     - _busy_state stays populated forever+#     - Every new POST /command request blocks on _main_thread_lock.acquire()+#       for its `timeout` seconds, then returns main_thread_busy+#     - From the user's perspective, the addin is dead until Fusion restarts+#+# Defense: a daemon thread checks _busy_state every 5s. If a busy state+# has been active longer than the per-command timeout + WATCHDOG_GRACE,+# we forcibly release _main_thread_lock so new requests can proceed.+# We can't unwedge the previously-stuck command (it's blocked in C++),+# but at least subsequent calls work without restarting Fusion.++WATCHDOG_GRACE = 30  # seconds beyond per-command timeout before force-release+_watchdog_stop = threading.Event()+_watchdog_thread = None+++def _watchdog_loop():+    """Force-release _main_thread_lock if a command has been busy too long."""+    while not _watchdog_stop.is_set():+        try:+            busy = _get_busy()+            if busy:+                cmd = busy.get("command", "")+                started = busy.get("started_at", 0.0)+                elapsed = time.time() - started+                # Get the timeout that applied to this command+                cmd_timeout = PER_COMMAND_TIMEOUT.get(cmd, COMMAND_TIMEOUT)+                if elapsed > cmd_timeout + WATCHDOG_GRACE:+                    try:+                        adsk.core.Application.log(+                            f"AdomBridge: WATCHDOG force-releasing _main_thread_lock — "+                            f"'{cmd}' held for {elapsed:.1f}s "+                            f"(> {cmd_timeout}+{WATCHDOG_GRACE}s grace). "+                            f"Fusion main thread likely wedged on native cloud call. "+                            f"Subsequent requests can now proceed; the wedged "+                            f"command will still leak its C++/Python state until "+                            f"Fusion restarts."+                        )+                    except Exception:+                        pass+                    # Clear the busy marker FIRST so /status no longer+                    # reports the stale command.+                    _clear_busy()+                    # Force-release. If the lock owner thread eventually+                    # unwedges and tries to release(), it'll get a+                    # RuntimeError which we accept as the cost of keeping+                    # subsequent requests flowing.+                    try:+                        _main_thread_lock.release()+                    except RuntimeError:+                        # Already released (race with the owner thread+                        # somehow making progress). Fine.+                        pass+                    # Also drop any pending request_ids so set_result()+                    # from a late-arriving wedged command can't leak.+                    with _lock:+                        _pending_request_ids.clear()+        except Exception:+            pass  # watchdog must never die+        _watchdog_stop.wait(5)  # check every 5s+++# Default per-command timeout. Heavy 3D exports (STEP/IGES/SAT/STL on+# panelized boards with 100+ placements) can take 120s+. Set generously.+COMMAND_TIMEOUT = 300  # seconds++# Per-command timeout overrides. Fast commands keep short timeouts so a+# hung main thread is surfaced quickly.+PER_COMMAND_TIMEOUT = {+    "get_app_state": 10,+    "document_info": 15,+    "take_screenshot": 30,+    "activate_document": 30,+    "close_document": 30,+    "close_all_documents": 60,+    # Exports can be slow on heavy designs+    "export_step": 300,+    "export_iges": 300,+    "export_sat": 300,+    "export_stl": 300,+    "export_3mf": 300,+    "export_usdz": 300,+    "export_obj": 300,+    "export_f3d": 300,+    "export_fbx": 300,+    "export_dxf": 120,+    "export_dwg": 120,+    "export_skp": 300,+    # Manufacturing exports (run EAGLE ULPs, can be slow)+    "export_gerbers": 180,+    "export_bom": 60,+    "export_cpl": 60,+    "export_board_image": 60,+    # Cloud tree walking / search — BFS over hundreds of folders+    "walk_cloud_tree": 600,+    "search_cloud_files": 180,+}+++def is_request_alive(request_id: str) -> bool:+    """Check whether an HTTP thread is still waiting for this request.++    Called from the main thread (CustomEventHandler) BEFORE doing heavy+    work, so we can skip exports whose HTTP waiter has already bailed.+    """+    with _lock:+        return request_id in _result_events+++def set_result(request_id: str, result: dict):+    """Called from the main thread (CustomEventHandler) to deliver a result."""+    with _lock:+        _last_main_thread_ts_local = time.time()+        # Update module-level timestamp+        global _last_main_thread_ts+        _last_main_thread_ts = _last_main_thread_ts_local++        _pending_request_ids.discard(request_id)++        event = _result_events.get(request_id)+        if event:+            # Normal path: HTTP thread is still waiting+            _result_data[request_id] = result+            event.set()+        # else: HTTP thread already timed out — discard result (don't leak)+++def _wait_for_result(request_id: str, timeout: float) -> dict:+    """Wait for the main thread to deliver a result for this request."""+    event = threading.Event()+    with _lock:+        _result_events[request_id] = event++    got_result = event.wait(timeout=timeout)++    with _lock:+        _result_events.pop(request_id, None)+        result = _result_data.pop(request_id, None)+        if not got_result:+            # Timed out — remove from pending so set_result() won't leak+            _pending_request_ids.discard(request_id)++    if not got_result or result is None:+        return {"success": False, "error": f"Command timed out after {timeout}s"}++    return result+++class AdomBridgeHandler(BaseHTTPRequestHandler):+    """HTTP handler for the add-in server."""++    def do_GET(self):+        if self.path == "/health":+            with _lock:+                pending = len(_pending_request_ids)+                last_ts = _last_main_thread_ts+            main_lock_held = _main_thread_lock.locked()++            # Determine main thread status+            now = time.time()+            if last_ts == 0.0 and pending == 0:+                main_status = "idle"  # No commands processed yet, none pending+            elif main_lock_held and pending > 0 and (last_ts == 0.0 or (now - last_ts) > COMMAND_TIMEOUT):+                main_status = "blocked"  # Commands pending but main thread not responding+            elif main_lock_held:+                main_status = "busy"  # A command is running on main thread+            else:+                main_status = "responsive"++            self._respond(200, {+                "status": "ok",+                "addin": "AdomBridge",+                "version": ADDIN_VERSION,+                "port": PORT,+                "main_thread": main_status,+                "main_thread_locked": main_lock_held,+                "pending_commands": pending,+                "main_thread_last_seen": round(last_ts, 1) if last_ts > 0 else None,+                "walk_progress": get_walk_progress(),+            })+        elif self.path == "/status":+            # Non-blocking busy probe — does NOT acquire _main_thread_lock.+            # Any number of callers (from any bridge/container) can hit this+            # concurrently. Returns which command holds the lock, how long+            # it's been running, and walk progress if applicable.+            busy = _get_busy()+            walk = get_walk_progress()+            if busy:+                elapsed = round(time.time() - busy["started_at"], 1)+                resp = {+                    "busy": True,+                    "version": ADDIN_VERSION,+                    "busyCommand": busy["command"],+                    "elapsedSeconds": elapsed,+                    "requestId": busy["request_id"],+                }+                if walk:+                    resp["walkProgress"] = walk+                elif busy["command"] in ("walk_cloud_tree", "search_cloud_files") and elapsed > 5:+                    # Walk/search was dispatched (HTTP thread set _busy_state) but+                    # the main thread hasn't started the handler yet (_walk_progress+                    # is still None). This means the custom event is queued but the+                    # main thread's event loop isn't processing it — typically+                    # because a modal dialog has its own nested event loop.+                    resp["mainThreadStalled"] = True+                    resp["stalledHint"] = (+                        "Command dispatched but main thread has not started processing. "+                        "A modal dialog is likely blocking Fusion's event loop. "+                        "Dismiss dialogs via fusion_dismiss_blocking_dialogs, "+                        "then the command will auto-resume."+                    )+                self._respond(200, resp)+            else:+                self._respond(200, {"busy": False, "version": ADDIN_VERSION})+        else:+            self._respond(404, {"error": "Not found"})++    def do_POST(self):+        if self.path != "/command":+            self._respond(404, {"error": "Not found"})+            return++        content_length = int(self.headers.get("Content-Length", 0))+        body = self.rfile.read(content_length)++        try:+            request = json.loads(body)+        except json.JSONDecodeError as e:+            self._respond(400, {"success": False, "error": f"Invalid JSON: {e}"})+            return++        command = request.get("command", "")+        args = request.get("args", {})+        request_id = str(uuid.uuid4())++        # Per-command timeout+        timeout = PER_COMMAND_TIMEOUT.get(command, COMMAND_TIMEOUT)+        # Allow caller override (useful for very large models)+        caller_timeout = request.get("timeout")+        if isinstance(caller_timeout, (int, float)) and caller_timeout > 0:+            timeout = float(caller_timeout)++        # Serialize CustomEvent fires through the main-thread lock so+        # requests don't stack. If another request is already in flight+        # to the main thread, we block here. We bound the wait so a+        # wedged main thread doesn't pile up indefinitely.+        lock_wait = timeout  # give us up to `timeout` seconds to acquire+        acquired = _main_thread_lock.acquire(timeout=lock_wait)+        if not acquired:+            busy = _get_busy()+            walk = get_walk_progress()+            elapsed = round(time.time() - busy["started_at"], 1) if busy else None+            error_msg = (+                f"Main thread busy — {busy['command']} running for {elapsed}s."+                if busy else+                f"Main thread busy — lock held for >{lock_wait}s."+            )+            resp = {+                "success": False,+                "error": error_msg,+                "errorCode": "main_thread_busy",+                "busyCommand": busy["command"] if busy else None,+                "elapsedSeconds": elapsed,+                "_hint": (+                    "Add-in is busy with a long-running command. Do NOT retry add-in commands. "+                    "Do NOT press Escape — the add-in is working, not stuck on a dialog. "+                    "Commands that still work: fusion_window_info, fusion_screenshot_fusion, "+                    "fusion_click_fusion, fusion_send_key, fusion_close_window."+                ),+            }+            if walk:+                resp["walkProgress"] = walk+            self._respond(200, resp)+            return++        try:+            _set_busy(command, request_id)++            # Track as pending before firing+            with _lock:+                _pending_request_ids.add(request_id)++            # Fire custom event to marshal to main thread+            try:+                _app.fireCustomEvent(+                    _custom_event_id,+                    json.dumps({"request_id": request_id, "command": command, "args": args}),+                )+            except Exception as e:+                with _lock:+                    _pending_request_ids.discard(request_id)+                self._respond(500, {"success": False, "error": f"Failed to fire event: {e}"})+                return++            # Wait for the main thread handler to deliver the result+            result = _wait_for_result(request_id, timeout=timeout)+            self._respond(200, result)+        finally:+            _clear_busy()+            _main_thread_lock.release()++    def _respond(self, status: int, data: dict):+        self.send_response(status)+        self.send_header("Content-Type", "application/json")+        self.end_headers()+        self.wfile.write(json.dumps(data).encode("utf-8"))++    def log_message(self, format, *args):+        # Suppress default HTTP logging to avoid cluttering Fusion's console+        pass+++def _adombridge_already_serving(timeout: float = 1.5) -> bool:+    """True if a live AdomBridge is already answering /health on PORT.++    Used to decide whether an EADDRINUSE means 'a duplicate of us is already+    up' (adopt: stand down quietly) vs 'some other process grabbed our port'+    (raise). Best-effort; any failure = treat as not-ours (fall through to+    raise so a real conflict is not hidden)."""+    try:+        with urllib.request.urlopen(f"http://127.0.0.1:{PORT}/health", timeout=timeout) as resp:+            body = json.loads(resp.read().decode("utf-8", "replace"))+        return str(body.get("addin", "")).lower() == "adombridge"+    except Exception:+        return False+++def start(custom_event_id: str, app: adsk.core.Application) -> threading.Thread:+    """Start the HTTP server on a background daemon thread."""+    global _server, _server_thread, _custom_event_id, _app, _watchdog_thread++    _custom_event_id = custom_event_id+    _app = app++    # ThreadingHTTPServer so /health and concurrent requests don't block+    # behind a slow request. Main-thread work is still serialized via+    # _main_thread_lock + CustomEvent marshaling.+    #+    # EADDRINUSE guard: Fusion can invoke this add-in's run() twice around+    # startup (observed on macOS at first-run sign-in), and a stale prior+    # Fusion can leave 8774 in TIME_WAIT for a moment. Either way a bare bind+    # raises OSError(48) which run() surfaces as a scary modal traceback.+    # Instead: if an AdomBridge is ALREADY serving 8774, this instance is a+    # duplicate — return quietly (the live one is the one to drive). If the+    # holder is something else, still raise so the real conflict is visible.+    try:+        _server = ThreadingHTTPServer(("127.0.0.1", PORT), AdomBridgeHandler)+    except OSError as e:+        if getattr(e, "errno", None) in (48, 98, 10048):  # EADDRINUSE mac/linux/win+            if _adombridge_already_serving():+                adsk.core.Application.log(+                    f"Adom Bridge: port {PORT} already served by a live AdomBridge — "+                    "this duplicate add-in load is standing down.")+                return None+        raise+    _server.daemon_threads = True++    _server_thread = threading.Thread(target=_server.serve_forever, daemon=True)+    _server_thread.start()++    # Start stale-lock watchdog (see _watchdog_loop docstring for rationale)+    _watchdog_stop.clear()+    _watchdog_thread = threading.Thread(target=_watchdog_loop, daemon=True, name="AdomBridge-Watchdog")+    _watchdog_thread.start()++    return _server_thread+++def stop():+    """Stop the HTTP server."""+    global _server+    _watchdog_stop.set()+    if _server:+        _server.shutdown()+        _server = None
addin/AdomBridge/resources/cam/._jlcpcb-2layers.camadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/resources/cam/._jlcpcb-4layers.camadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/resources/cam/jlcpcb-2layers.camadded+245
@@ -0,0 +1,245 @@+{+    "author": {+        "email": "[email protected]",+        "name": "JLCPCB"+    },+    "description": {+        "EN": "<b>JLCPCB 2-Layer CAM job</b><p>\n\nFor Eagle 8.6.0 to 9.6.2<p>\n\nTop Copper:      pcbname.GTL<br>\nTop Solder Mask: pcbname.GTS<br>\nTop Silkscreen:  pcbname.GTO<br>\nTop Paste:       pcbname.GTP<p>\n\nBottom Copper:      pcbname.GBL<br>\nBottom Solder Mask: pcbname.GBS<br>\nBottom Silkscreen:  pcbname.GBO<br>\nBottom Paste:       pcbname.GBP<p>\n\nProfile: pcbname.GKO (Dimension (20) and Milling (46) layers are used)<p>\nDrill Layer: pcbname.XLN (Both plated and non-plated holes are merged in this file)<p>\n\nPlease refer to <a href=\"https://support.jlcpcb.com/article/43-how-to-export-eagle-pcb-to-gerber-files\">How to Generate Gerber and Drill Files from Eagle</a> for more information.<p>\n\nEmail: [email protected]<p>\nLast updated: 2020/11/18"+    },+    "output_type": "zip",+    "outputs": [+        {+            "compress_output": true,+            "export_cad_netlist": true,+            "export_eda_component_attributes": true,+            "export_eda_data": true,+            "export_eda_footprint_names": true,+            "export_eda_net_attributes": true,+            "export_job_name_instead_of_product_model_name": true,+            "export_layer_features_count": true,+            "export_neutral_net_names": false,+            "export_step_profile_board_cutouts": true,+            "export_step_profile_from_board_shape": true,+            "export_text_attributes": true,+            "export_unique_id": true,+            "export_unit": true,+            "filename_prefix": "CAMOutputs/ODBFiles",+            "generate_job_file": true,+            "odb_format_version": "V8.1+",+            "output_name": "emmamorris_v11",+            "output_type": "odb++",+            "outputs": [+            ],+            "prepend_netattributes_with_numbersign": true,+            "use_teamhub_location": false+        },+        {+            "filename_prefix": "GerberJob",+            "format_specifier": {+                "decimal": 4,+                "integer": 3+            },+            "generate_job_file": true,+            "output_type": "gerber",+            "outputs": [+                {+                    "board_outline": true,+                    "config": {+                        "file_function": "Profile",+                        "plating": "non-plated"+                    },+                    "filename_format": "%N.GKO",+                    "layers": [+                        20+                    ],+                    "milling": true,+                    "name": "Board Outline",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Copper",+                        "layer": 1,+                        "layer_details": "mixed",+                        "layer_type": "top"+                    },+                    "filename_format": "%N.GTL",+                    "layers": [+                        1,+                        18,+                        17+                    ],+                    "name": "Top Copper",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Copper",+                        "layer": 2,+                        "layer_details": "mixed",+                        "layer_type": "bottom"+                    },+                    "filename_format": "%N.GBL",+                    "layers": [+                        16,+                        17,+                        18+                    ],+                    "name": "Bottom Copper",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Soldermask",+                        "index": 1,+                        "layer_type": "top"+                    },+                    "filename_format": "%N.GTS",+                    "layers": [+                        29+                    ],+                    "name": "Soldermask Top",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Soldermask",+                        "index": 1,+                        "layer_type": "bottom"+                    },+                    "filename_format": "%N.GBS",+                    "layers": [+                        30+                    ],+                    "name": "Soldermask Bottom",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Paste",+                        "layer_type": "top"+                    },+                    "filename_format": "%N.GTP",+                    "layers": [+                        31+                    ],+                    "milling": false,+                    "name": "Solderpaste Top",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Paste",+                        "layer_type": "bottom"+                    },+                    "filename_format": "%N.GBP",+                    "layers": [+                        32+                    ],+                    "milling": false,+                    "name": "Solderpaste Bottom",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Legend",+                        "index": 1,+                        "layer_type": "top"+                    },+                    "filename_format": "%N.GTO",+                    "layers": [+                        21,+                        25+                    ],+                    "milling": false,+                    "name": "Silkscreen Top",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Legend",+                        "index": 1,+                        "layer_type": "bottom"+                    },+                    "filename_format": "%N.GBO",+                    "layers": [+                        22,+                        26+                    ],+                    "milling": false,+                    "name": "Silkscreen Bottom",+                    "polarity": "positive",+                    "type": "gerber_layer"+                }+            ],+            "version": "RS274X"+        },+        {+            "extension_type": "pdf",+            "filename_prefix": "CAMOutputs/ImageFiles",+            "fit_to_Page": true,+            "monochrome": true,+            "output_type": "image",+            "outputs": [+            ],+            "page_size": "A4",+            "pdf_filename": "%N"+        },+        {+            "filename_prefix": "",+            "format_specifier": {+                "decimal": 3,+                "integer": 3+            },+            "output_type": "drill",+            "outputs": [+                {+                    "drills": {+                        "NPTH": true,+                        "PTH": true,+                        "VIA": true+                    },+                    "filename_format": "%N.XLN",+                    "layers": {+                        "from": 1,+                        "to": 16+                    },+                    "name": "Excellon",+                    "type": "excellon"+                }+            ]+        },+        {+            "filename_prefix": "CAMOutputs/Assembly",+            "output_type": "assembly",+            "outputs": [+            ]+        },+        {+            "filename_prefix": "CAMOutputs/DrawingFiles",+            "output_type": "drawing",+            "outputs": [+            ]+        }+    ],+    "timestamp": "2020-11-12T14:32:05",+    "type": "EAGLE CAM job",+    "units": "metric",+    "version": "9.2.0"+}
addin/AdomBridge/resources/cam/jlcpcb-4layers.camadded+262
@@ -0,0 +1,262 @@+{+    "author": {+        "email": "[email protected]",+        "name": "JLCPCB"+    },+    "description": {+        "EN": "<b>JLCPCB 4-Layer CAM job</b><p>\n\nFor Eagle 8.6.0 to 9.6.2<p>\n\nTop Copper:           pcbname_copper_l1.GTL<br>\nInner Copper Layer 1: pcbname_copper_l2.G1<br>\nInner Copper Layer 2: pcbname_copper_l3.G2<br>\nBottom Copper:        pcbname_copper_l4.GBL<p>\n\nDrill File: pcbname_drill.XLN (Both plated and non-plated holes are merged into this file)<p>\n\nSilkscreen Bottom: pcbname_Legend_Bot.GBO<br>\nSilkscreen Top:    pcbname_Legend_Top.GTO<br>\nPaste Bottom:      pcbname_Paste_Bot.GBP<br>\nPaste Top:         pcbname_Paste_Top.GTP<p>\n\nBoard Outline: pcbname_Profile_NP.GKO (Includes Dimension (20) and Milling (46) layers)<p>\n\nSoldermask Bottom: pcbname_Soldermask_Bot.GBS<br>\nSoldermask Top:    pcbname_Soldermask_Top.GTS<p>\n\nPlease refer to <a href=\"https://support.jlcpcb.com/article/43-how-to-export-eagle-pcb-to-gerber-files\">How to Generate Gerber and Drill Files from Eagle</a> for more information.<p>\n\nEmail: [email protected]<p>\nLast updated: 2020/11/18"+    },+    "output_type": "zip",+    "outputs": [+        {+            "filename_prefix": "GerberJob",+            "format_specifier": {+                "decimal": 4,+                "integer": 3+            },+            "generate_job_file": true,+            "output_type": "gerber",+            "outputs": [+                {+                    "board_outline": true,+                    "config": {+                        "file_function": "Profile",+                        "plating": "non-plated"+                    },+                    "filename_format": "%N_%FF.GKO",+                    "layers": [+                        46,+                        20+                    ],+                    "milling": true,+                    "name": "Board Outline",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Copper",+                        "layer": 1,+                        "layer_details": "mixed",+                        "layer_type": "top"+                    },+                    "filename_format": "%N_%FF.GTL",+                    "layers": [+                        1,+                        18,+                        17+                    ],+                    "name": "Top Copper",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "advanced_options": {+                        "mirror": false,+                        "offset_x": 0,+                        "offset_y": 0,+                        "rotate": false,+                        "upside_down": false+                    },+                    "board_outline": false,+                    "config": {+                        "file_function": "Copper",+                        "layer": 2,+                        "layer_details": "mixed",+                        "layer_type": "Inner"+                    },+                    "filename_format": "%N_%FF.G1",+                    "layers": [+                        2,+                        17,+                        18+                    ],+                    "milling": false,+                    "name": "Inner Copper Layer 1",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "advanced_options": {+                        "mirror": false,+                        "offset_x": 0,+                        "offset_y": 0,+                        "rotate": false,+                        "upside_down": false+                    },+                    "board_outline": false,+                    "config": {+                        "file_function": "Copper",+                        "layer": 3,+                        "layer_details": "mixed",+                        "layer_type": "Inner"+                    },+                    "filename_format": "%N_%FF.G2",+                    "layers": [+                        15,+                        17,+                        18+                    ],+                    "milling": false,+                    "name": "Inner Copper Layer 2",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Copper",+                        "layer": 4,+                        "layer_details": "mixed",+                        "layer_type": "bottom"+                    },+                    "filename_format": "%N_%FF.GBL",+                    "layers": [+                        16,+                        17,+                        18+                    ],+                    "name": "Bottom Copper",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Soldermask",+                        "index": 1,+                        "layer_type": "top"+                    },+                    "filename_format": "%N_%FF.GTS",+                    "layers": [+                        29+                    ],+                    "name": "Soldermask Top",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Soldermask",+                        "index": 1,+                        "layer_type": "bottom"+                    },+                    "filename_format": "%N_%FF.GBS",+                    "layers": [+                        30+                    ],+                    "name": "Soldermask Bottom",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Paste",+                        "layer_type": "top"+                    },+                    "filename_format": "%N_%FF.GTP",+                    "layers": [+                        31+                    ],+                    "milling": false,+                    "name": "Solderpaste Top",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Paste",+                        "layer_type": "bottom"+                    },+                    "filename_format": "%N_%FF.GBP",+                    "layers": [+                        32+                    ],+                    "milling": false,+                    "name": "Solderpaste Bottom",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Legend",+                        "index": 1,+                        "layer_type": "top"+                    },+                    "filename_format": "%N_%FF.GTO",+                    "layers": [+                        21,+                        25+                    ],+                    "milling": false,+                    "name": "Silkscreen Top",+                    "polarity": "positive",+                    "type": "gerber_layer"+                },+                {+                    "board_outline": false,+                    "config": {+                        "file_function": "Legend",+                        "index": 1,+                        "layer_type": "bottom"+                    },+                    "filename_format": "%N_%FF.GBO",+                    "layers": [+                        22,+                        26+                    ],+                    "milling": false,+                    "name": "Silkscreen Bottom",+                    "polarity": "positive",+                    "type": "gerber_layer"+                }+            ],+            "version": "RS274X"+        },+        {+            "filename_prefix": "",+            "format_specifier": {+                "decimal": 3,+                "integer": 3+            },+            "output_type": "drill",+            "outputs": [+                {+                    "drills": {+                        "NPTH": true,+                        "PTH": true,+                        "VIA": true+                    },+                    "filename_format": "%N_drill.XLN",+                    "layers": {+                        "from": 1,+                        "to": 16+                    },+                    "name": "Drill File",+                    "type": "excellon"+                }+            ]+        },+        {+            "filename_prefix": "CAMOutputs/Assembly",+            "output_type": "assembly",+            "outputs": [+            ]+        },+        {+            "filename_prefix": "CAMOutputs/DrawingFiles",+            "output_type": "drawing",+            "outputs": [+            ]+        }+    ],+    "timestamp": "2020-11-18T10:32:27",+    "type": "EAGLE CAM job",+    "units": "metric",+    "version": "9.2.0"+}
addin/AdomBridge/resources/dru/._Adom-InstaPCB-2-Layer.edruadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/resources/dru/._Adom-InstaPCB-4-Layer.edruadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/resources/dru/._AdomDefaults-jlcpcb-2layers-accurate.edruadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/resources/dru/._AdomDefaults-jlcpcb-4layers-accurate.edruadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/resources/dru/Adom-InstaPCB-2-Layer.edruadded+165
@@ -0,0 +1,165 @@+<?xml version="1.0" encoding="utf-8"?>+<!DOCTYPE designrules SYSTEM "eagle.dtd">+<eagle version="9.7.0">+<designrules name="Adom-InstaPCB-2-Layer.edru">+<classes>+<class number="0" name="default">+</class>+<class number="1" name="pwr">+</class>+</classes>+<rules>+<rulecategory type="Copper Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Keepout Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Solder-Mask Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Dimension Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Drill Distance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Restrict Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Minimum Drill Size" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Minimum Copper Width" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Acute Angle" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Air-Wire" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Small Gap" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Wire Stub" manualdrc="yes" livedrc="no"/>+ <rulecategory type="Matched Lengths" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Via Restrict Clearance" manualdrc="yes" livedrc="yes"/>+ <rule type="Minimum Copper Width" enabled="yes" priority="0" onescope="classes=1" value="0.1mm" preferredvalue="0.3mm" check_polywidth="no" name="Trace size for Power"/>+ <rule type="Minimum Copper Width" builtin_ruleid="14" enabled="yes" priority="1" value="0.1mm" preferredvalue="0.2mm" check_polywidth="no" name="minimum-copper-width-1"/>+ <rule type="Minimum Drill Size" enabled="yes" priority="0" onescope="is_via" value="0.15mm" preferredvalue="0.3mm" name="Min Via hole size on 2-layer"/>+ <rule type="Minimum Drill Size" enabled="no" priority="1" onescope="all" value="0.5mm" preferredvalue="0.5mm" name="Min Non-plated holes"/>+ <rule type="Minimum Drill Size" builtin_ruleid="15" enabled="yes" priority="2" value="0.15mm" preferredvalue="0.3mm" name="minimum-drill-size-1"/>+ <rule type="Acute Angle" builtin_ruleid="16" enabled="no" priority="0" name="acute-angle-1"/>+ <rule type="Wire Stub" builtin_ruleid="17" enabled="yes" priority="0" name="wire-stub-1"/>+ <rule type="Air-Wire" builtin_ruleid="19" enabled="yes" priority="0" name="air-wire-1"/>+ <rule type="Matched Lengths" builtin_ruleid="20" enabled="yes" priority="0" tolerance="10mm" gapfactor="2.5" name="matched-lengths-1"/>+ <rule type="Copper Clearance" enabled="no" priority="0" onescope="all" otherscope="all" value="0.25mm" preferredvalue="0.25mm" samesignal="yes" bothscope="all" name="Same-net track spacing"/>+ <rule type="Copper Clearance" builtin_ruleid="0" enabled="yes" priority="1" onescope="is_wire_polygon" otherscope="is_wire_polygon" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-1"/>+ <rule type="Copper Clearance" builtin_ruleid="1" enabled="yes" priority="2" onescope="is_wire_polygon" otherscope="is_pad_smd" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-2"/>+ <rule type="Copper Clearance" builtin_ruleid="2" enabled="yes" priority="3" onescope="is_wire_polygon" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-3"/>+ <rule type="Copper Clearance" builtin_ruleid="3" enabled="yes" priority="4" onescope="is_pad_smd" otherscope="is_pad_smd" value="0.15mm" preferredvalue="0.15mm" samesignal="no" name="copper-clearance-4"/>+ <rule type="Copper Clearance" builtin_ruleid="4" enabled="yes" priority="5" onescope="is_pad_smd" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-5"/>+ <rule type="Copper Clearance" builtin_ruleid="5" enabled="yes" priority="6" onescope="is_via" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-6"/>+ <rule type="Copper Clearance" builtin_ruleid="6" enabled="yes" priority="7" onescope="is_smd" otherscope="is_pad" value="0.1mm" preferredvalue="0.2mm" samesignal="yes" name="copper-clearance-7"/>+ <rule type="Copper Clearance" builtin_ruleid="7" enabled="yes" priority="8" onescope="is_smd" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="yes" name="copper-clearance-8"/>+ <rule type="Copper Clearance" builtin_ruleid="8" enabled="yes" priority="9" onescope="is_smd" otherscope="is_smd" value="0.1mm" preferredvalue="0.2mm" samesignal="yes" name="copper-clearance-9"/>+ <rule type="Dimension Clearance" builtin_ruleid="9" enabled="yes" priority="0" value="0.2mm" preferredvalue="0.4mm" name="dimension-clearance-1"/>+ <rule type="Via Restrict Clearance" builtin_ruleid="21" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="via-restrict-clearance-1"/>+ <rule type="Restrict Clearance" builtin_ruleid="10" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="restrict-clearance-1"/>+ <rule type="Small Gap" builtin_ruleid="18" enabled="yes" priority="0" name="small-gap-1"/>+ <rule type="Solder-Mask Clearance" builtin_ruleid="11" enabled="no" priority="0" value="0mil" preferredvalue="0mil" check_name="yes" check_value="no" name="solder-mask-clearance-1"/>+ <rule type="Drill Distance" builtin_ruleid="12" enabled="yes" priority="0" value="0.2mm" preferredvalue="0.2mm" name="drill-distance-1"/>+ <rule type="Keepout Clearance" builtin_ruleid="13" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="keepout-clearance-1"/>+ </rules>+<param name="mdWireWire" value="0.1mm"/>+<param name="mdWirePad" value="0.1mm"/>+<param name="mdWireVia" value="0.1mm"/>+<param name="mdPadPad" value="0.15mm"/>+<param name="mdPadVia" value="0.1mm"/>+<param name="mdViaVia" value="0.1mm"/>+<param name="mdSmdPad" value="0.1mm"/>+<param name="mdSmdVia" value="0.1mm"/>+<param name="mdSmdSmd" value="0.1mm"/>+<param name="mdCopperDimension" value="0.2mm"/>+<param name="mdDrill" value="0.2mm"/>+<param name="msWidth" value="0.1mm"/>+<param name="msDrill" value="0.15mm"/>+<param name="dpMaxLengthDifference" value="10mm"/>+<param name="dpGapFactor" value="2.5"/>+<description language="en">Adom InstaPCB 2-Layer design rules++Board thickness: 1.6mm+Copper weight: 1oz (35um)++There are 2 net classes of:+These are valuable when using the auto-router if you tell it what wires are in the Power class+- Default (Min 0.1mm track width, Preferred 0.2mm)+- Power (Min 0.1mm track width, Preferred 0.3mm)+Min. track width and spacing (1 oz)+0.10 / 0.10 mm (4 / 4 mil)++Vias:+- Min 0.15mm via allowed on 2-layer now with InstaPCB+- We made preferred 0.25mm, although InstaPCB says 0.2 is preferred+Min. Via hole size/diameter 2-layer: 0.15mm hole size / 0.25mm via diameter++Drill:+Drill Diameter - 2-layer: 0.15 – 6.3 mm+Min. Non-plated holes - 0.50mm+Holes with diameter ≥ 6.3 mm are CNC routed from a smaller drilled hole.++Annular Ring:+Vias: 0.1mm annular ring is InstaPCB min+Pads (through-hole parts): 0.18mm annular ring is InstaPCB min+However, they prefer 0.25mm annular ring or above++</description>+<param name="layerSetup" value="(1*16)"/>+<param name="mtCopper" value="0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm"/>+<param name="mtIsolate" value="1.6mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm"/>+<param name="mdViaViaSameLayer" value="6mil"/>+<param name="mnLayersViaInSmd" value="2"/>+<param name="mdSmdStop" value="0mil"/>+<param name="msMicroVia" value="0.3mm"/>+<param name="msBlindViaRatio" value="0.5"/>+<param name="rvPadTop" value="0"/>+<param name="rvPadInner" value="0"/>+<param name="rvPadBottom" value="0"/>+<param name="rvViaOuter" value="0"/>+<param name="rvViaInner" value="0"/>+<param name="rvMicroViaOuter" value="0"/>+<param name="rvMicroViaInner" value="0"/>+<param name="rlMinPadTop" value="0.18mm"/>+<param name="rlMaxPadTop" value="80mil"/>+<param name="rlMinPadInner" value="0.18mm"/>+<param name="rlMaxPadInner" value="20mil"/>+<param name="rlMinPadBottom" value="0.18mm"/>+<param name="rlMaxPadBottom" value="80mil"/>+<param name="rlMinViaOuter" value="0.1mm"/>+<param name="rlMaxViaOuter" value="20mil"/>+<param name="rlMinViaInner" value="0.1mm"/>+<param name="rlMaxViaInner" value="20mil"/>+<param name="rlMinMicroViaOuter" value="0.1mm"/>+<param name="rlMaxMicroViaOuter" value="20mil"/>+<param name="rlMinMicroViaInner" value="0.1mm"/>+<param name="rlMaxMicroViaInner" value="20mil"/>+<param name="psTop" value="-1"/>+<param name="psBottom" value="-1"/>+<param name="psFirst" value="-1"/>+<param name="psElongationLong" value="100"/>+<param name="psElongationOffset" value="100"/>+<param name="mvStopFrame" value="0"/>+<param name="mvCreamFrame" value="0"/>+<param name="mlMinStopFrame" value="0.038mm"/>+<param name="mlMaxStopFrame" value="4mil"/>+<param name="mlMinCreamFrame" value="0mil"/>+<param name="mlMaxCreamFrame" value="0mil"/>+<param name="mlViaStopLimit" value="0.5mm"/>+<param name="srRoundness" value="0"/>+<param name="srMinRoundness" value="0mil"/>+<param name="srMaxRoundness" value="0mil"/>+<param name="slThermalIsolate" value="10mil"/>+<param name="slThermalsForVias" value="0"/>+<param name="checkAngle" value="0"/>+<param name="checkRestrict" value="1"/>+<param name="checkStop" value="0"/>+<param name="checkValues" value="0"/>+<param name="checkNames" value="1"/>+<param name="checkWireStubs" value="1"/>+<param name="checkPolygonWidth" value="0"/>+<param name="useDiameter" value="13"/>+<param name="removeAnnularRing" value="0"/>+<param name="maxErrors" value="50"/>+<layerstackup name="Default Layer Stack" type="Standard Stackup" display_unit="mic" roughness_model="0">+ <layerdef type="Signal" id="{5a9a536d-8422-4e27-a88e-724a65556bb4}" layer="1" name="Top" locally_modified_material="yes">+ <material name="User Defined" thickness="0.035mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <layerdef type="Core" id="{4559ea01-630e-4693-8c35-7a0c3eba0b8a}" layer="1" name="Dielectric-1" locally_modified_material="yes">+ <material name="User Defined" construction="" thickness="1.6mm" resin="50%" dielectric_constant_1g="4.5" dissipation_factor_1g="0.02" glass_transition_temperature="125degC" source="User"/>+</layerdef>+ <layerdef type="Signal" id="{77284764-ed3d-425b-85b1-529ddeb5fc5a}" layer="16" name="Bottom" locally_modified_material="yes">+ <material name="User Defined" thickness="0.035mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <viadef name="Thru 1:16" startlayer="1" stoplayer="16" complement="no"/>+ </layerstackup>+ </designrules>+</eagle>
addin/AdomBridge/resources/dru/Adom-InstaPCB-4-Layer.edruadded+183
@@ -0,0 +1,183 @@+<?xml version="1.0" encoding="utf-8"?>+<!DOCTYPE designrules SYSTEM "eagle.dtd">+<eagle version="9.7.0">+<designrules name="Adom-InstaPCB-4-Layer.edru">+<classes>+<class number="0" name="default">+</class>+<class number="1" name="pwr">+</class>+</classes>+<rules>+<rulecategory type="Copper Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Keepout Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Solder-Mask Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Dimension Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Drill Distance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Restrict Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Minimum Drill Size" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Minimum Copper Width" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Acute Angle" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Air-Wire" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Small Gap" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Wire Stub" manualdrc="yes" livedrc="no"/>+ <rulecategory type="Matched Lengths" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Via Restrict Clearance" manualdrc="yes" livedrc="yes"/>+ <rule type="Minimum Copper Width" enabled="yes" priority="0" onescope="classes=1" value="0.09mm" preferredvalue="0.3mm" check_polywidth="no" name="Trace size for Power"/>+ <rule type="Minimum Copper Width" builtin_ruleid="14" enabled="yes" priority="1" value="0.09mm" preferredvalue="0.2mm" check_polywidth="no" name="minimum-copper-width-1"/>+ <rule type="Minimum Drill Size" enabled="yes" priority="0" onescope="is_via" value="0.15mm" preferredvalue="0.2mm" name="Min Via hole size on 4-layer"/>+ <rule type="Minimum Drill Size" enabled="no" priority="1" onescope="all" value="0.5mm" preferredvalue="0.5mm" name="Min Non-plated holes"/>+ <rule type="Minimum Drill Size" builtin_ruleid="15" enabled="yes" priority="2" value="0.15mm" preferredvalue="0.25mm" name="minimum-drill-size-1"/>+ <rule type="Acute Angle" builtin_ruleid="16" enabled="no" priority="0" name="acute-angle-1"/>+ <rule type="Wire Stub" builtin_ruleid="17" enabled="yes" priority="0" name="wire-stub-1"/>+ <rule type="Air-Wire" builtin_ruleid="19" enabled="yes" priority="0" name="air-wire-1"/>+ <rule type="Matched Lengths" builtin_ruleid="20" enabled="yes" priority="0" tolerance="10mm" gapfactor="2.5" name="matched-lengths-1"/>+ <rule type="Copper Clearance" enabled="yes" priority="0" onescope="all" otherscope="all" value="0.25mm" preferredvalue="0.25mm" samesignal="yes" bothscope="all" name="Same-net track spacing"/>+ <rule type="Copper Clearance" builtin_ruleid="0" enabled="yes" priority="1" onescope="is_wire_polygon" otherscope="is_wire_polygon" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-1"/>+ <rule type="Copper Clearance" builtin_ruleid="1" enabled="yes" priority="2" onescope="is_wire_polygon" otherscope="is_pad_smd" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-2"/>+ <rule type="Copper Clearance" builtin_ruleid="2" enabled="yes" priority="3" onescope="is_wire_polygon" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-3"/>+ <rule type="Copper Clearance" builtin_ruleid="3" enabled="yes" priority="4" onescope="is_pad_smd" otherscope="is_pad_smd" value="0.15mm" preferredvalue="0.15mm" samesignal="no" name="copper-clearance-4"/>+ <rule type="Copper Clearance" builtin_ruleid="4" enabled="yes" priority="5" onescope="is_pad_smd" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-5"/>+ <rule type="Copper Clearance" builtin_ruleid="5" enabled="yes" priority="6" onescope="is_via" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-6"/>+ <rule type="Copper Clearance" builtin_ruleid="6" enabled="yes" priority="7" onescope="is_smd" otherscope="is_pad" value="0.1mm" preferredvalue="0.2mm" samesignal="yes" name="copper-clearance-7"/>+ <rule type="Copper Clearance" builtin_ruleid="7" enabled="yes" priority="8" onescope="is_smd" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="yes" name="copper-clearance-8"/>+ <rule type="Copper Clearance" builtin_ruleid="8" enabled="yes" priority="9" onescope="is_smd" otherscope="is_smd" value="0.1mm" preferredvalue="0.2mm" samesignal="yes" name="copper-clearance-9"/>+ <rule type="Dimension Clearance" builtin_ruleid="9" enabled="yes" priority="0" value="0.2mm" preferredvalue="0.2mm" name="dimension-clearance-1"/>+ <rule type="Via Restrict Clearance" builtin_ruleid="21" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="via-restrict-clearance-1"/>+ <rule type="Restrict Clearance" builtin_ruleid="10" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="restrict-clearance-1"/>+ <rule type="Small Gap" builtin_ruleid="18" enabled="yes" priority="0" name="small-gap-1"/>+ <rule type="Solder-Mask Clearance" builtin_ruleid="11" enabled="no" priority="0" value="0mil" preferredvalue="0mil" check_name="yes" check_value="no" name="solder-mask-clearance-1"/>+ <rule type="Drill Distance" builtin_ruleid="12" enabled="yes" priority="0" value="0.2mm" preferredvalue="0.2mm" name="drill-distance-1"/>+ <rule type="Keepout Clearance" builtin_ruleid="13" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="keepout-clearance-1"/>+ </rules>+<param name="mdWireWire" value="0.1mm"/>+<param name="mdWirePad" value="0.1mm"/>+<param name="mdWireVia" value="0.1mm"/>+<param name="mdPadPad" value="0.15mm"/>+<param name="mdPadVia" value="0.1mm"/>+<param name="mdViaVia" value="0.1mm"/>+<param name="mdSmdPad" value="0.1mm"/>+<param name="mdSmdVia" value="0.1mm"/>+<param name="mdSmdSmd" value="0.1mm"/>+<param name="mdCopperDimension" value="0.2mm"/>+<param name="mdDrill" value="0.2mm"/>+<param name="msWidth" value="0.1mm"/>+<param name="msDrill" value="0.15mm"/>+<param name="dpMaxLengthDifference" value="10mm"/>+<param name="dpGapFactor" value="2.5"/>+<description language="en">Adom InstaPCB 4-Layer design rules++Board thickness: 1.6mm+Copper weight: 1oz (35um)++Track width spacing for 4-layer:+Multilayer: 0.09 / 0.09 mm (3.5 / 3.5 mil). 3 mil is acceptable in BGA fan-outs.+BGA pad diameter ≥ 0.25 mm+BGA pad to trace clearance min. 0.09 mm for multilayer boards+Vias can be placed within BGA pads using filled and plated-over vias++There are 2 net classes of:+These are valuable when using the auto-router if you tell it what wires are in the Power class+- Default (Min 0.09mm track width, Preferred 0.2mm)+- Power (Min 0.09mm track width, Preferred 0.3mm)+Min. track width and spacing (1 oz)+0.10 / 0.10 mm (4 / 4 mil)++Vias:+- Min 0.15mm via allowed on 4-layer now with InstaPCB+- We made preferred 0.25mm, although InstaPCB says 0.2 is preferred+Min. Via hole size/diameter 4-layer: 0.15mm hole size / 0.25mm via diameter++Drill:+Drill Diameter - 4-layer: 0.15 – 6.3 mm+Min. Non-plated holes - 0.50mm+Holes with diameter ≥ 6.3 mm are CNC routed from a smaller drilled hole.++Annular Ring:+Vias: 0.1mm annular ring is InstaPCB min+Pads (through-hole parts): 0.18mm annular ring is InstaPCB min+However, they prefer 0.25mm annular ring or above++</description>+<param name="layerSetup" value="(1*16)"/>+<param name="mtCopper" value="0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm"/>+<param name="mtIsolate" value="1.6mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm"/>+<param name="mdViaViaSameLayer" value="6mil"/>+<param name="mnLayersViaInSmd" value="2"/>+<param name="mdSmdStop" value="0mil"/>+<param name="msMicroVia" value="0.3mm"/>+<param name="msBlindViaRatio" value="0.5"/>+<param name="rvPadTop" value="0"/>+<param name="rvPadInner" value="0"/>+<param name="rvPadBottom" value="0"/>+<param name="rvViaOuter" value="0"/>+<param name="rvViaInner" value="0"/>+<param name="rvMicroViaOuter" value="0"/>+<param name="rvMicroViaInner" value="0"/>+<param name="rlMinPadTop" value="0.18mm"/>+<param name="rlMaxPadTop" value="80mil"/>+<param name="rlMinPadInner" value="0.18mm"/>+<param name="rlMaxPadInner" value="20mil"/>+<param name="rlMinPadBottom" value="0.18mm"/>+<param name="rlMaxPadBottom" value="80mil"/>+<param name="rlMinViaOuter" value="0.1mm"/>+<param name="rlMaxViaOuter" value="20mil"/>+<param name="rlMinViaInner" value="0.1mm"/>+<param name="rlMaxViaInner" value="20mil"/>+<param name="rlMinMicroViaOuter" value="0.1mm"/>+<param name="rlMaxMicroViaOuter" value="20mil"/>+<param name="rlMinMicroViaInner" value="0.1mm"/>+<param name="rlMaxMicroViaInner" value="20mil"/>+<param name="psTop" value="-1"/>+<param name="psBottom" value="-1"/>+<param name="psFirst" value="-1"/>+<param name="psElongationLong" value="100"/>+<param name="psElongationOffset" value="100"/>+<param name="mvStopFrame" value="0"/>+<param name="mvCreamFrame" value="0"/>+<param name="mlMinStopFrame" value="0.038mm"/>+<param name="mlMaxStopFrame" value="4mil"/>+<param name="mlMinCreamFrame" value="0mil"/>+<param name="mlMaxCreamFrame" value="0mil"/>+<param name="mlViaStopLimit" value="0.5mm"/>+<param name="srRoundness" value="0"/>+<param name="srMinRoundness" value="0mil"/>+<param name="srMaxRoundness" value="0mil"/>+<param name="slThermalIsolate" value="10mil"/>+<param name="slThermalsForVias" value="0"/>+<param name="checkAngle" value="0"/>+<param name="checkRestrict" value="1"/>+<param name="checkStop" value="0"/>+<param name="checkValues" value="0"/>+<param name="checkNames" value="1"/>+<param name="checkWireStubs" value="1"/>+<param name="checkPolygonWidth" value="0"/>+<param name="useDiameter" value="13"/>+<param name="removeAnnularRing" value="0"/>+<param name="maxErrors" value="50"/>+<layerstackup name="Default Layer Stack" type="Standard Stackup" display_unit="mic" roughness_model="0">+ <layerdef type="Signal" id="{aacc8861-39b2-48dc-8db3-f266478ef2b8}" layer="1" name="Top" locally_modified_material="yes">+ <material name="User Defined" thickness="0.035mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <layerdef type="Prepreg" id="{adcb8555-47a8-402a-8dc6-0ded7ce8d84c}" layer="2" name="Dielectric-2" locally_modified_material="yes">+ <material name="User Defined" glass_style="" thickness="0.2mm" resin="50%" dielectric_constant_1g="4.5" dissipation_factor_1g="0.02" glass_transition_temperature="125degC" source="User"/>+</layerdef>+ <layerdef type="Signal" id="{5ffaa838-d681-4063-bb48-2b039e6cf0b6}" layer="2" name="Route2" locally_modified_material="yes">+ <material name="User Defined" thickness="0.0175mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <layerdef type="Core" id="{80a6f05f-0ad2-4112-8467-cea4561d9bb9}" layer="1" name="Dielectric-1" locally_modified_material="yes">+ <material name="User Defined" construction="" thickness="1.065mm" resin="50%" dielectric_constant_1g="4.5" dissipation_factor_1g="0.02" glass_transition_temperature="125degC" source="User"/>+</layerdef>+ <layerdef type="Signal" id="{37bd35fe-018e-4cdb-8b86-5ed09ec84a8a}" layer="15" name="Route15" locally_modified_material="yes">+ <material name="User Defined" thickness="0.0175mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <layerdef type="Prepreg" id="{61cdb834-2e83-4ba7-98a3-15b69ca17485}" layer="3" name="Dielectric-3" locally_modified_material="yes">+ <material name="User Defined" glass_style="" thickness="0.2mm" resin="50%" dielectric_constant_1g="4.5" dissipation_factor_1g="0.02" glass_transition_temperature="125degC" source="User"/>+</layerdef>+ <layerdef type="Signal" id="{633df6dd-d049-4e1e-91be-c70449465674}" layer="16" name="Bottom" locally_modified_material="yes">+ <material name="User Defined" thickness="0.035mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <viadef name="Thru 1:16" startlayer="1" stoplayer="16" complement="no"/>+ </layerstackup>+ </designrules>+</eagle>
addin/AdomBridge/resources/dru/AdomDefaults-jlcpcb-2layers-accurate.edruadded+165
@@ -0,0 +1,165 @@+<?xml version="1.0" encoding="utf-8"?>+<!DOCTYPE designrules SYSTEM "eagle.dtd">+<eagle version="9.7.0">+<designrules name="AdomDefaults-jlcpcb-2layers-accurate.edru">+<classes>+<class number="0" name="default">+</class>+<class number="1" name="pwr">+</class>+</classes>+<rules>+<rulecategory type="Copper Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Keepout Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Solder-Mask Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Dimension Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Drill Distance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Restrict Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Minimum Drill Size" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Minimum Copper Width" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Acute Angle" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Air-Wire" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Small Gap" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Wire Stub" manualdrc="yes" livedrc="no"/>+ <rulecategory type="Matched Lengths" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Via Restrict Clearance" manualdrc="yes" livedrc="yes"/>+ <rule type="Minimum Copper Width" enabled="yes" priority="0" onescope="classes=1" value="0.1mm" preferredvalue="0.3mm" check_polywidth="no" name="Trace size for Power"/>+ <rule type="Minimum Copper Width" builtin_ruleid="14" enabled="yes" priority="1" value="0.1mm" preferredvalue="0.2mm" check_polywidth="no" name="minimum-copper-width-1"/>+ <rule type="Minimum Drill Size" enabled="yes" priority="0" onescope="is_via" value="0.15mm" preferredvalue="0.3mm" name="Min Via hole size on 2-layer"/>+ <rule type="Minimum Drill Size" enabled="no" priority="1" onescope="all" value="0.5mm" preferredvalue="0.5mm" name="Min Non-plated holes"/>+ <rule type="Minimum Drill Size" builtin_ruleid="15" enabled="yes" priority="2" value="0.15mm" preferredvalue="0.3mm" name="minimum-drill-size-1"/>+ <rule type="Acute Angle" builtin_ruleid="16" enabled="no" priority="0" name="acute-angle-1"/>+ <rule type="Wire Stub" builtin_ruleid="17" enabled="yes" priority="0" name="wire-stub-1"/>+ <rule type="Air-Wire" builtin_ruleid="19" enabled="yes" priority="0" name="air-wire-1"/>+ <rule type="Matched Lengths" builtin_ruleid="20" enabled="yes" priority="0" tolerance="10mm" gapfactor="2.5" name="matched-lengths-1"/>+ <rule type="Copper Clearance" enabled="no" priority="0" onescope="all" otherscope="all" value="0.25mm" preferredvalue="0.25mm" samesignal="yes" bothscope="all" name="Same-net track spacing"/>+ <rule type="Copper Clearance" builtin_ruleid="0" enabled="yes" priority="1" onescope="is_wire_polygon" otherscope="is_wire_polygon" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-1"/>+ <rule type="Copper Clearance" builtin_ruleid="1" enabled="yes" priority="2" onescope="is_wire_polygon" otherscope="is_pad_smd" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-2"/>+ <rule type="Copper Clearance" builtin_ruleid="2" enabled="yes" priority="3" onescope="is_wire_polygon" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-3"/>+ <rule type="Copper Clearance" builtin_ruleid="3" enabled="yes" priority="4" onescope="is_pad_smd" otherscope="is_pad_smd" value="0.15mm" preferredvalue="0.15mm" samesignal="no" name="copper-clearance-4"/>+ <rule type="Copper Clearance" builtin_ruleid="4" enabled="yes" priority="5" onescope="is_pad_smd" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-5"/>+ <rule type="Copper Clearance" builtin_ruleid="5" enabled="yes" priority="6" onescope="is_via" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-6"/>+ <rule type="Copper Clearance" builtin_ruleid="6" enabled="yes" priority="7" onescope="is_smd" otherscope="is_pad" value="0.1mm" preferredvalue="0.2mm" samesignal="yes" name="copper-clearance-7"/>+ <rule type="Copper Clearance" builtin_ruleid="7" enabled="yes" priority="8" onescope="is_smd" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="yes" name="copper-clearance-8"/>+ <rule type="Copper Clearance" builtin_ruleid="8" enabled="yes" priority="9" onescope="is_smd" otherscope="is_smd" value="0.1mm" preferredvalue="0.2mm" samesignal="yes" name="copper-clearance-9"/>+ <rule type="Dimension Clearance" builtin_ruleid="9" enabled="yes" priority="0" value="0.2mm" preferredvalue="0.4mm" name="dimension-clearance-1"/>+ <rule type="Via Restrict Clearance" builtin_ruleid="21" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="via-restrict-clearance-1"/>+ <rule type="Restrict Clearance" builtin_ruleid="10" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="restrict-clearance-1"/>+ <rule type="Small Gap" builtin_ruleid="18" enabled="yes" priority="0" name="small-gap-1"/>+ <rule type="Solder-Mask Clearance" builtin_ruleid="11" enabled="no" priority="0" value="0mil" preferredvalue="0mil" check_name="yes" check_value="no" name="solder-mask-clearance-1"/>+ <rule type="Drill Distance" builtin_ruleid="12" enabled="yes" priority="0" value="0.2mm" preferredvalue="0.2mm" name="drill-distance-1"/>+ <rule type="Keepout Clearance" builtin_ruleid="13" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="keepout-clearance-1"/>+ </rules>+<param name="mdWireWire" value="0.1mm"/>+<param name="mdWirePad" value="0.1mm"/>+<param name="mdWireVia" value="0.1mm"/>+<param name="mdPadPad" value="0.15mm"/>+<param name="mdPadVia" value="0.1mm"/>+<param name="mdViaVia" value="0.1mm"/>+<param name="mdSmdPad" value="0.1mm"/>+<param name="mdSmdVia" value="0.1mm"/>+<param name="mdSmdSmd" value="0.1mm"/>+<param name="mdCopperDimension" value="0.2mm"/>+<param name="mdDrill" value="0.2mm"/>+<param name="msWidth" value="0.1mm"/>+<param name="msDrill" value="0.15mm"/>+<param name="dpMaxLengthDifference" value="10mm"/>+<param name="dpGapFactor" value="2.5"/>+<description language="en">Adom Defaults for JLCPCB design rules (2 layers)++Board thickness: 1.6mm+Copper weight: 1oz (35um)++There are 2 net classes of:+These are valuable when using the auto-router if you tell it what wires are in the Power class+- Default (Min 0.1mm track width, Preferred 0.2mm)+- Power (Min 0.1mm track width, Preferred 0.3mm)+Min. track width and spacing (1 oz)+0.10 / 0.10 mm (4 / 4 mil)++Vias:+- Min 0.15mm via allowed on 2-layer now with JLC+- We made preferred 0.25mm, although JLC says 0.2 is preferred+Min. Via hole size/diameter 2-layer: 0.15mm hole size / 0.25mm via diameter++Drill:+Drill Diameter - 2-layer: 0.15 – 6.3 mm+Min. Non-plated holes - 0.50mm+Holes with diameter ≥ 6.3 mm are CNC routed from a smaller drilled hole.++Annular Ring:+Vias: 0.1mm annular ring is JLC min+Pads (through-hole parts): 0.18mm annular ring is JLC min+However, they prefer 0.25mm annular ring or above++</description>+<param name="layerSetup" value="(1*16)"/>+<param name="mtCopper" value="0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm"/>+<param name="mtIsolate" value="1.6mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm"/>+<param name="mdViaViaSameLayer" value="6mil"/>+<param name="mnLayersViaInSmd" value="2"/>+<param name="mdSmdStop" value="0mil"/>+<param name="msMicroVia" value="0.3mm"/>+<param name="msBlindViaRatio" value="0.5"/>+<param name="rvPadTop" value="0"/>+<param name="rvPadInner" value="0"/>+<param name="rvPadBottom" value="0"/>+<param name="rvViaOuter" value="0"/>+<param name="rvViaInner" value="0"/>+<param name="rvMicroViaOuter" value="0"/>+<param name="rvMicroViaInner" value="0"/>+<param name="rlMinPadTop" value="0.18mm"/>+<param name="rlMaxPadTop" value="80mil"/>+<param name="rlMinPadInner" value="0.18mm"/>+<param name="rlMaxPadInner" value="20mil"/>+<param name="rlMinPadBottom" value="0.18mm"/>+<param name="rlMaxPadBottom" value="80mil"/>+<param name="rlMinViaOuter" value="0.1mm"/>+<param name="rlMaxViaOuter" value="20mil"/>+<param name="rlMinViaInner" value="0.1mm"/>+<param name="rlMaxViaInner" value="20mil"/>+<param name="rlMinMicroViaOuter" value="0.1mm"/>+<param name="rlMaxMicroViaOuter" value="20mil"/>+<param name="rlMinMicroViaInner" value="0.1mm"/>+<param name="rlMaxMicroViaInner" value="20mil"/>+<param name="psTop" value="-1"/>+<param name="psBottom" value="-1"/>+<param name="psFirst" value="-1"/>+<param name="psElongationLong" value="100"/>+<param name="psElongationOffset" value="100"/>+<param name="mvStopFrame" value="0"/>+<param name="mvCreamFrame" value="0"/>+<param name="mlMinStopFrame" value="0.038mm"/>+<param name="mlMaxStopFrame" value="4mil"/>+<param name="mlMinCreamFrame" value="0mil"/>+<param name="mlMaxCreamFrame" value="0mil"/>+<param name="mlViaStopLimit" value="0.5mm"/>+<param name="srRoundness" value="0"/>+<param name="srMinRoundness" value="0mil"/>+<param name="srMaxRoundness" value="0mil"/>+<param name="slThermalIsolate" value="10mil"/>+<param name="slThermalsForVias" value="0"/>+<param name="checkAngle" value="0"/>+<param name="checkRestrict" value="1"/>+<param name="checkStop" value="0"/>+<param name="checkValues" value="0"/>+<param name="checkNames" value="1"/>+<param name="checkWireStubs" value="1"/>+<param name="checkPolygonWidth" value="0"/>+<param name="useDiameter" value="13"/>+<param name="removeAnnularRing" value="0"/>+<param name="maxErrors" value="50"/>+<layerstackup name="Default Layer Stack" type="Standard Stackup" display_unit="mic" roughness_model="0">+ <layerdef type="Signal" id="{5a9a536d-8422-4e27-a88e-724a65556bb4}" layer="1" name="Top" locally_modified_material="yes">+ <material name="User Defined" thickness="0.035mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <layerdef type="Core" id="{4559ea01-630e-4693-8c35-7a0c3eba0b8a}" layer="1" name="Dielectric-1" locally_modified_material="yes">+ <material name="User Defined" construction="" thickness="1.6mm" resin="50%" dielectric_constant_1g="4.5" dissipation_factor_1g="0.02" glass_transition_temperature="125degC" source="User"/>+</layerdef>+ <layerdef type="Signal" id="{77284764-ed3d-425b-85b1-529ddeb5fc5a}" layer="16" name="Bottom" locally_modified_material="yes">+ <material name="User Defined" thickness="0.035mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <viadef name="Thru 1:16" startlayer="1" stoplayer="16" complement="no"/>+ </layerstackup>+ </designrules>+</eagle>
addin/AdomBridge/resources/dru/AdomDefaults-jlcpcb-4layers-accurate.edruadded+183
@@ -0,0 +1,183 @@+<?xml version="1.0" encoding="utf-8"?>+<!DOCTYPE designrules SYSTEM "eagle.dtd">+<eagle version="9.7.0">+<designrules name="AdomDefaults-jlcpcb-4layers-accurate.edru">+<classes>+<class number="0" name="default">+</class>+<class number="1" name="pwr">+</class>+</classes>+<rules>+<rulecategory type="Copper Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Keepout Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Solder-Mask Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Dimension Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Drill Distance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Restrict Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Minimum Drill Size" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Minimum Copper Width" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Acute Angle" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Air-Wire" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Small Gap" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Wire Stub" manualdrc="yes" livedrc="no"/>+ <rulecategory type="Matched Lengths" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Via Restrict Clearance" manualdrc="yes" livedrc="yes"/>+ <rule type="Minimum Copper Width" enabled="yes" priority="0" onescope="classes=1" value="0.09mm" preferredvalue="0.3mm" check_polywidth="no" name="Trace size for Power"/>+ <rule type="Minimum Copper Width" builtin_ruleid="14" enabled="yes" priority="1" value="0.09mm" preferredvalue="0.2mm" check_polywidth="no" name="minimum-copper-width-1"/>+ <rule type="Minimum Drill Size" enabled="yes" priority="0" onescope="is_via" value="0.15mm" preferredvalue="0.2mm" name="Min Via hole size on 4-layer"/>+ <rule type="Minimum Drill Size" enabled="no" priority="1" onescope="all" value="0.5mm" preferredvalue="0.5mm" name="Min Non-plated holes"/>+ <rule type="Minimum Drill Size" builtin_ruleid="15" enabled="yes" priority="2" value="0.15mm" preferredvalue="0.25mm" name="minimum-drill-size-1"/>+ <rule type="Acute Angle" builtin_ruleid="16" enabled="no" priority="0" name="acute-angle-1"/>+ <rule type="Wire Stub" builtin_ruleid="17" enabled="yes" priority="0" name="wire-stub-1"/>+ <rule type="Air-Wire" builtin_ruleid="19" enabled="yes" priority="0" name="air-wire-1"/>+ <rule type="Matched Lengths" builtin_ruleid="20" enabled="yes" priority="0" tolerance="10mm" gapfactor="2.5" name="matched-lengths-1"/>+ <rule type="Copper Clearance" enabled="yes" priority="0" onescope="all" otherscope="all" value="0.25mm" preferredvalue="0.25mm" samesignal="yes" bothscope="all" name="Same-net track spacing"/>+ <rule type="Copper Clearance" builtin_ruleid="0" enabled="yes" priority="1" onescope="is_wire_polygon" otherscope="is_wire_polygon" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-1"/>+ <rule type="Copper Clearance" builtin_ruleid="1" enabled="yes" priority="2" onescope="is_wire_polygon" otherscope="is_pad_smd" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-2"/>+ <rule type="Copper Clearance" builtin_ruleid="2" enabled="yes" priority="3" onescope="is_wire_polygon" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-3"/>+ <rule type="Copper Clearance" builtin_ruleid="3" enabled="yes" priority="4" onescope="is_pad_smd" otherscope="is_pad_smd" value="0.15mm" preferredvalue="0.15mm" samesignal="no" name="copper-clearance-4"/>+ <rule type="Copper Clearance" builtin_ruleid="4" enabled="yes" priority="5" onescope="is_pad_smd" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-5"/>+ <rule type="Copper Clearance" builtin_ruleid="5" enabled="yes" priority="6" onescope="is_via" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-6"/>+ <rule type="Copper Clearance" builtin_ruleid="6" enabled="yes" priority="7" onescope="is_smd" otherscope="is_pad" value="0.1mm" preferredvalue="0.2mm" samesignal="yes" name="copper-clearance-7"/>+ <rule type="Copper Clearance" builtin_ruleid="7" enabled="yes" priority="8" onescope="is_smd" otherscope="is_via" value="0.1mm" preferredvalue="0.2mm" samesignal="yes" name="copper-clearance-8"/>+ <rule type="Copper Clearance" builtin_ruleid="8" enabled="yes" priority="9" onescope="is_smd" otherscope="is_smd" value="0.1mm" preferredvalue="0.2mm" samesignal="yes" name="copper-clearance-9"/>+ <rule type="Dimension Clearance" builtin_ruleid="9" enabled="yes" priority="0" value="0.2mm" preferredvalue="0.2mm" name="dimension-clearance-1"/>+ <rule type="Via Restrict Clearance" builtin_ruleid="21" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="via-restrict-clearance-1"/>+ <rule type="Restrict Clearance" builtin_ruleid="10" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="restrict-clearance-1"/>+ <rule type="Small Gap" builtin_ruleid="18" enabled="yes" priority="0" name="small-gap-1"/>+ <rule type="Solder-Mask Clearance" builtin_ruleid="11" enabled="no" priority="0" value="0mil" preferredvalue="0mil" check_name="yes" check_value="no" name="solder-mask-clearance-1"/>+ <rule type="Drill Distance" builtin_ruleid="12" enabled="yes" priority="0" value="0.2mm" preferredvalue="0.2mm" name="drill-distance-1"/>+ <rule type="Keepout Clearance" builtin_ruleid="13" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="keepout-clearance-1"/>+ </rules>+<param name="mdWireWire" value="0.1mm"/>+<param name="mdWirePad" value="0.1mm"/>+<param name="mdWireVia" value="0.1mm"/>+<param name="mdPadPad" value="0.15mm"/>+<param name="mdPadVia" value="0.1mm"/>+<param name="mdViaVia" value="0.1mm"/>+<param name="mdSmdPad" value="0.1mm"/>+<param name="mdSmdVia" value="0.1mm"/>+<param name="mdSmdSmd" value="0.1mm"/>+<param name="mdCopperDimension" value="0.2mm"/>+<param name="mdDrill" value="0.2mm"/>+<param name="msWidth" value="0.1mm"/>+<param name="msDrill" value="0.15mm"/>+<param name="dpMaxLengthDifference" value="10mm"/>+<param name="dpGapFactor" value="2.5"/>+<description language="en">Adom Defaults for JLCPCB design rules (4 layers)++Board thickness: 1.6mm+Copper weight: 1oz (35um)++Track width spacing for 4-layer:+Multilayer: 0.09 / 0.09 mm (3.5 / 3.5 mil). 3 mil is acceptable in BGA fan-outs.+BGA pad diameter ≥ 0.25 mm+BGA pad to trace clearance min. 0.09 mm for multilayer boards+Vias can be placed within BGA pads using filled and plated-over vias++There are 2 net classes of:+These are valuable when using the auto-router if you tell it what wires are in the Power class+- Default (Min 0.09mm track width, Preferred 0.2mm)+- Power (Min 0.09mm track width, Preferred 0.3mm)+Min. track width and spacing (1 oz)+0.10 / 0.10 mm (4 / 4 mil)++Vias:+- Min 0.15mm via allowed on 4-layer now with JLC+- We made preferred 0.25mm, although JLC says 0.2 is preferred+Min. Via hole size/diameter 4-layer: 0.15mm hole size / 0.25mm via diameter++Drill:+Drill Diameter - 4-layer: 0.15 – 6.3 mm+Min. Non-plated holes - 0.50mm+Holes with diameter ≥ 6.3 mm are CNC routed from a smaller drilled hole.++Annular Ring:+Vias: 0.1mm annular ring is JLC min+Pads (through-hole parts): 0.18mm annular ring is JLC min+However, they prefer 0.25mm annular ring or above++</description>+<param name="layerSetup" value="(1*16)"/>+<param name="mtCopper" value="0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm"/>+<param name="mtIsolate" value="1.6mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm"/>+<param name="mdViaViaSameLayer" value="6mil"/>+<param name="mnLayersViaInSmd" value="2"/>+<param name="mdSmdStop" value="0mil"/>+<param name="msMicroVia" value="0.3mm"/>+<param name="msBlindViaRatio" value="0.5"/>+<param name="rvPadTop" value="0"/>+<param name="rvPadInner" value="0"/>+<param name="rvPadBottom" value="0"/>+<param name="rvViaOuter" value="0"/>+<param name="rvViaInner" value="0"/>+<param name="rvMicroViaOuter" value="0"/>+<param name="rvMicroViaInner" value="0"/>+<param name="rlMinPadTop" value="0.18mm"/>+<param name="rlMaxPadTop" value="80mil"/>+<param name="rlMinPadInner" value="0.18mm"/>+<param name="rlMaxPadInner" value="20mil"/>+<param name="rlMinPadBottom" value="0.18mm"/>+<param name="rlMaxPadBottom" value="80mil"/>+<param name="rlMinViaOuter" value="0.1mm"/>+<param name="rlMaxViaOuter" value="20mil"/>+<param name="rlMinViaInner" value="0.1mm"/>+<param name="rlMaxViaInner" value="20mil"/>+<param name="rlMinMicroViaOuter" value="0.1mm"/>+<param name="rlMaxMicroViaOuter" value="20mil"/>+<param name="rlMinMicroViaInner" value="0.1mm"/>+<param name="rlMaxMicroViaInner" value="20mil"/>+<param name="psTop" value="-1"/>+<param name="psBottom" value="-1"/>+<param name="psFirst" value="-1"/>+<param name="psElongationLong" value="100"/>+<param name="psElongationOffset" value="100"/>+<param name="mvStopFrame" value="0"/>+<param name="mvCreamFrame" value="0"/>+<param name="mlMinStopFrame" value="0.038mm"/>+<param name="mlMaxStopFrame" value="4mil"/>+<param name="mlMinCreamFrame" value="0mil"/>+<param name="mlMaxCreamFrame" value="0mil"/>+<param name="mlViaStopLimit" value="0.5mm"/>+<param name="srRoundness" value="0"/>+<param name="srMinRoundness" value="0mil"/>+<param name="srMaxRoundness" value="0mil"/>+<param name="slThermalIsolate" value="10mil"/>+<param name="slThermalsForVias" value="0"/>+<param name="checkAngle" value="0"/>+<param name="checkRestrict" value="1"/>+<param name="checkStop" value="0"/>+<param name="checkValues" value="0"/>+<param name="checkNames" value="1"/>+<param name="checkWireStubs" value="1"/>+<param name="checkPolygonWidth" value="0"/>+<param name="useDiameter" value="13"/>+<param name="removeAnnularRing" value="0"/>+<param name="maxErrors" value="50"/>+<layerstackup name="Default Layer Stack" type="Standard Stackup" display_unit="mic" roughness_model="0">+ <layerdef type="Signal" id="{aacc8861-39b2-48dc-8db3-f266478ef2b8}" layer="1" name="Top" locally_modified_material="yes">+ <material name="User Defined" thickness="0.035mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <layerdef type="Prepreg" id="{adcb8555-47a8-402a-8dc6-0ded7ce8d84c}" layer="2" name="Dielectric-2" locally_modified_material="yes">+ <material name="User Defined" glass_style="" thickness="0.2mm" resin="50%" dielectric_constant_1g="4.5" dissipation_factor_1g="0.02" glass_transition_temperature="125degC" source="User"/>+</layerdef>+ <layerdef type="Signal" id="{5ffaa838-d681-4063-bb48-2b039e6cf0b6}" layer="2" name="Route2" locally_modified_material="yes">+ <material name="User Defined" thickness="0.0175mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <layerdef type="Core" id="{80a6f05f-0ad2-4112-8467-cea4561d9bb9}" layer="1" name="Dielectric-1" locally_modified_material="yes">+ <material name="User Defined" construction="" thickness="1.065mm" resin="50%" dielectric_constant_1g="4.5" dissipation_factor_1g="0.02" glass_transition_temperature="125degC" source="User"/>+</layerdef>+ <layerdef type="Signal" id="{37bd35fe-018e-4cdb-8b86-5ed09ec84a8a}" layer="15" name="Route15" locally_modified_material="yes">+ <material name="User Defined" thickness="0.0175mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <layerdef type="Prepreg" id="{61cdb834-2e83-4ba7-98a3-15b69ca17485}" layer="3" name="Dielectric-3" locally_modified_material="yes">+ <material name="User Defined" glass_style="" thickness="0.2mm" resin="50%" dielectric_constant_1g="4.5" dissipation_factor_1g="0.02" glass_transition_temperature="125degC" source="User"/>+</layerdef>+ <layerdef type="Signal" id="{633df6dd-d049-4e1e-91be-c70449465674}" layer="16" name="Bottom" locally_modified_material="yes">+ <material name="User Defined" thickness="0.035mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <viadef name="Thru 1:16" startlayer="1" stoplayer="16" complement="no"/>+ </layerstackup>+ </designrules>+</eagle>
addin/AdomBridge/resources/ulp/._detect_layers.ulpadded
⋯ 1 unchanged line ⋯
addin/AdomBridge/resources/ulp/detect_layers.ulpadded+81
@@ -0,0 +1,81 @@+// ULP script to detect board layers+// Usage: run detect_layers.ulp output_file_path++if (argc < 1) {+    dlgMessageBox("Please provide an output file path!\nUsage: run detect_layers.ulp <output_file>");+    exit(1);+}++string output_file = argv[1];++if (board) {+    board(B) {+        int copper_layer_count = 0;+        string layer_info = "";+        +        // Simple approach: check for traces/wires on each layer+        int layer_has_traces[];+        +        // Check for traces on each layer+        B.signals(S) {+            S.wires(W) {+                layer_has_traces[W.layer] = 1;+            }+        }+        +        // Check all layers and determine which are copper layers+        B.layers(L) {+            int is_copper = 0;+            +            // More robust layer detection based on Eagle's standard layer numbering:+            // Layer 1: Top copper (always present)+            // Layer 16: Bottom copper (always present) +            // Layers 2-15: Inner copper layers (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)+            // Standard 4-layer uses: 1 (top), 2 (inner1), 15 (inner2), 16 (bottom)+            // Standard 6-layer uses: 1, 2, 3, 14, 15, 16+            // Standard 8-layer uses: 1, 2, 3, 4, 13, 14, 15, 16+            +            if (L.number == 1 || L.number == 16) {+                // Top and bottom layers - always copper if they exist+                is_copper = 1;+                copper_layer_count++;+            } else if (L.number >= 2 && L.number <= 15) {+                // Potential inner copper layers - only count if they have traces+                if (layer_has_traces[L.number]) {+                    is_copper = 1;+                    copper_layer_count++;+                }+            }+            +            // Add layer info to JSON+            if (layer_info != "") {+                layer_info += ",";+            }+            +            string layer_num, is_copper_str, has_traces_str;+            sprintf(layer_num, "%d", L.number);+            sprintf(is_copper_str, "%d", is_copper);+            sprintf(has_traces_str, "%d", layer_has_traces[L.number]);+            +            layer_info += "{\"number\":" + layer_num + ",\"name\":\"" + L.name + "\",\"isCopper\":" + is_copper_str + ",\"hasTraces\":" + has_traces_str + "}";+        }+        +        // Write results to file+        output(output_file) {+            printf("{\n");+            printf("  \"copperLayerCount\": %d,\n", copper_layer_count);+            printf("  \"boardName\": \"%s\",\n", B.name);+            printf("  \"layers\": [%s]\n", layer_info);+            printf("}\n");+        }+    }+} else {+    // No board found - write error info+    output(output_file) {+        printf("{\n");+        printf("  \"error\": \"No board found\",\n");+        printf("  \"copperLayerCount\": 0,\n");+        printf("  \"layers\": []\n");+        printf("}\n");+    }+}
adom-bridge-fusion-manifest.jsonadded+13
@@ -0,0 +1,13 @@+{+    "manifest_version": 1,+    "name": "fusion360",+    "version": "1.8.2",+    "url": "https://wiki.adom.inc/download/adom/adom-desktop-fusion-bridge/1.8.2/adom-bridge-fusion-v1.8.2.zip",+    "sha256": "6f92b2315e17739b6b9e800e6754d92b5eaef5b461918ca364b9a98cb2ec7a7d",+    "size": 292380,+    "verbPrefixes": [+        "fusion_"+    ],+    "healthEndpoint": "/status",+    "released_at": "2026-07-24T10:30:00Z"+}\ No newline at end of file
aps.pyadded+1416
@@ -0,0 +1,1416 @@+"""Autodesk Platform Services (APS) cloud-file search for the Fusion bridge.++Gives the fusion bridge its OWN fast, server-indexed cloud search (the+Data Management API) instead of the slow folder-by-folder walk that+fusion_walk_cloud_tree / fusion_search_cloud_files do. Works even when+Fusion is closed — this is pure HTTPS against APS.++Auth: the bridge runs its OWN 3-legged PKCE OAuth (public client, no client+secret). Only the APS Client ID is stored. We can't reuse Fusion's in-session+token — Autodesk DPAPI-encrypts that store with app entropy on purpose — so the+bridge owns its own login. One-time: register a Desktop/PKCE app at+aps.autodesk.com (Data Management API enabled, callback below), put the Client+ID in config, then fusion_aps_signin once.++Verbs (CLI fusion_aps_*  ->  bridge command aps_*):+  fusion_aps_status                 - configured? signed in? token live?+  fusion_aps_set_client_id {clientId}+  fusion_aps_signin                 - opens browser; bg listener stores the token+  fusion_aps_search {query, hubId?, projectId?, limit?}+  fusion_aps_get {path}             - raw authenticated GET (dev/verify helper)++No third-party deps — stdlib only (the bridge must run on stock Python).+"""++import base64+import hashlib+import json+import os+import secrets+import subprocess+import threading+import time+import urllib.parse+import urllib.request+import urllib.error+import webbrowser+from concurrent.futures import ThreadPoolExecutor+from http.server import BaseHTTPRequestHandler, HTTPServer+from pathlib import Path++_usage_lock = threading.Lock()++# ── Constants ────────────────────────────────────────────────────────────────+APS_BASE = "https://developer.api.autodesk.com"+AUTH_URL = f"{APS_BASE}/authentication/v2/authorize"+TOKEN_URL = f"{APS_BASE}/authentication/v2/token"++# Fixed callback — MUST match the registered APS app exactly. 8910 is AD-native+# APS's port; the bridge uses its own so the two never collide.+# Fixed callback ports — tried in order at sign-in; the FIRST free one is bound.+# All of these (× localhost AND 127.0.0.1) are registered on the APS app, so a+# port collision on any user's machine just falls through to the next — no failed+# sign-ins. 8917 avoids AD's own APS on 8910; all verified free + outside Windows'+# reserved/excluded ranges (5357, 27339, 50000-50059) on a real box.+REDIRECT_PORTS = [8917, 8918, 8920]+REDIRECT_PATH = "/fusion-aps/callback"+_active_redirect_uri = None  # set to the bound port's URI when a sign-in starts+++def _redirect_uri(port: int) -> str:+    return f"http://localhost:{port}{REDIRECT_PATH}"+++def all_registered_callbacks() -> list:+    """Every callback URL that must be registered on the APS app (localhost + 127.0.0.1)."""+    out = []+    for p in REDIRECT_PORTS:+        out.append(f"http://localhost:{p}{REDIRECT_PATH}")+        out.append(f"http://127.0.0.1:{p}{REDIRECT_PATH}")+    return out+# data:read is enough for search/browse/recent/file_info/versions/download.+# data:write + data:create are needed for create_folder/upload. Including them in+# the scope means a user who signed in under the old read-only scope must run+# fusion_aps_signin once more before the write verbs work (read verbs keep working).+SCOPES = "data:read data:write data:create"++# ⛔ CLOUD SEARCH IS APS-ONLY, AND SETTING APS UP IS MANDATORY - NOT OPTIONAL. This is returned by+# every cloud verb when APS isn't ready, as a HARD directive (John 2026-07-14, emphatic: an AI saw APS+# "Not configured", shrugged, and fell back to enumerating app.data.dataProjects/dataFiles via+# fusion_run_modeling_script - which HOLDS FUSION'S MAIN THREAD for minutes, TIMES OUT, and locks the+# app. That is the deprecated method and it is BANNED for cloud search). APS must work every time.+APS_REQUIRED_HINT = (+    "APS IS MANDATORY for cloud file search/browse/recent - SET IT UP, do not give up, do not fall back. "+    "⛔ NEVER enumerate cloud files via app.data (dataProjects/dataFiles) in fusion_run_modeling_script: "+    "the DEPRECATED method holds Fusion's main thread for minutes, times out, and locks the app. "+    "AUTO-RECOVER APS instead: (1) NOT configured? The org Client ID is a PUBLIC PKCE id - pull it from a "+    "peer that has it: read ~/.adom/fusion-aps/config.json (key 'client_id') off another AD desktop (adom-"+    "desktop status lists them) via shell_execute/pull_file, then fusion_aps_set_client_id {clientId}. "+    "(2) fusion_aps_signin -> open the returned authUrl in the user's REAL browser with a warm Autodesk "+    "session; INSTALL + USE the adom-browser-extension (nbrowser/ABE, https://wiki.adom.inc/adom/adom-"+    "browser-extension) to drive it reliably (recommend it - coordinate-clicking a browser is fragile). "+    "The localhost listener captures the token; poll fusion_aps_status until signedIn:true. (3) retry. "+    "If authorize returns AUTH-001 'client_id does not have access to the api product': the APS app at "+    "aps.autodesk.com/myapps lost its Data Management API product - re-commit its API Access + Save, wait "+    "a few minutes to propagate, retry."+)+++def _aps_auth001_recovery_hint(client_id: str) -> str:+    """The programmatic self-heal for APS AUTH-001, returned by start_signin the moment it detects the+    app lost its Data Management API PRODUCT (John 2026-07-14: an AI figured this out live over an hour;+    no future AI should have to). The bridge can't drive aps.autodesk.com itself, so this is the exact+    ABE/nbrowser recipe the calling AI runs - deterministic, verified live."""+    return (+        "⚠ APS AUTH-001 - the APS app (Client ID " + (client_id[:8] + "...") + ") LOST its Data Management "+        "API product, so authorize fails BEFORE any login. This is fixable; here is the exact recovery "+        "(this one genuinely needs ABE/nbrowser: recovery CLICKS and EVALs inside the portal, which the "+        "extension-free nbrowser_open_os_window cannot do - it only opens a URL. If the extension is not "+        "installed, install adom-browser-extension first; ABE can do it automatically, roughly a 5-minute "+        "AI-driven process. Alternatively walk the USER through steps 1-3 by hand): "+        "(1) nbrowser_open_window {sessionId, thread, purpose, profile:<the warm Edge/Chrome profile>, "+        "url:'https://aps.autodesk.com/myapps/'} and open the app whose Client ID is this one. "+        "(2) On the app's App-settings page, API Access section: confirm 'Data Management API' is checked, "+        "then FORCE a re-commit - nbrowser_eval a click on the VISIBLE 'Save changes' button (filter "+        "buttons by /save changes/i AND offsetParent!==null; the bare text matches ~9 hidden duplicates so "+        "text-click is ambiguous). If Save is disabled, toggle any one unneeded API off first to dirty the "+        "form. (3) WAIT ~1-3 min for Autodesk to propagate. (4) Retry fusion_aps_signin; authorize now "+        "reaches the CONSENT screen ('<app> is requesting permission ... View/Manage/Write your data ... "+        "Allow') - nbrowser_navigate the session to the new authUrl, then nbrowser_click 'Allow'; the URL "+        "flips to localhost:<port>/fusion-aps/callback?code=... and the bridge captures the token. "+        "(5) Poll fusion_aps_status until signedIn:true. Verified live 2026-07-14."+    )+++def _probe_authorize_auth001(auth_url: str) -> bool:+    """Server-side probe: does this app's /authorize return AUTH-001 (no api-product access)? The check+    happens BEFORE any user login, so the bridge can detect a broken app WITHOUT a browser and hand back+    the recovery recipe immediately (instead of the AI opening a browser only to hit the JSON error).+    A healthy app 302-redirects to login/consent (no AUTH-001 body); a broken one returns the AUTH-001+    JSON. Never raises; returns False on any ambiguity (don't false-block a real sign-in)."""+    class _NoRedirect(urllib.request.HTTPRedirectHandler):+        def redirect_request(self, *a, **k):+            return None  # a redirect means the app is FINE - stop, don't chase the login page+    try:+        opener = urllib.request.build_opener(_NoRedirect)+        try:+            body = opener.open(urllib.request.Request(auth_url), timeout=8).read().decode("utf-8", "replace")+        except urllib.error.HTTPError as e:+            if e.code in (301, 302, 303, 307, 308):+                return False  # redirect to login = healthy app+            body = (e.read() or b"").decode("utf-8", "replace")+        except Exception:+            return False+        return ("AUTH-001" in body) or ("does not have access to the api product" in body.lower())+    except Exception:+        return False++APS_DIR = Path(os.path.expanduser("~")) / ".adom" / "fusion-aps"+CONFIG_FILE = APS_DIR / "config.json"+TOKENS_FILE = APS_DIR / "tokens.json"+USAGE_FILE = APS_DIR / "usage.json"+# Which browser+profile the user's Autodesk sign-in ACTUALLY succeeded in. Power users+# run many browsers and many profiles; the OS default is usually NOT the one holding the+# warm Autodesk/SSO session. So we REMEMBER the browser+profile that worked and reuse it,+# instead of blindly firing webbrowser.open (which hits the OS default and forces a fresh+# login in the wrong place). Set on a successful driven sign-in; reused on every later one.+SIGNIN_BROWSER_FILE = APS_DIR / "signin-browser.json"+++def load_signin_browser() -> dict | None:+    """The remembered {name, exe, profileDir, newWindow} that last authed to Autodesk, or None."""+    try:+        return json.loads(SIGNIN_BROWSER_FILE.read_text(encoding="utf-8"))+    except Exception:+        return None+++def save_signin_browser(pref: dict) -> bool:+    """Remember the browser+profile that just worked, so the next sign-in reuses it."""+    try:+        APS_DIR.mkdir(parents=True, exist_ok=True)+        keep = {k: pref.get(k) for k in ("name", "exe", "profileDir", "newWindow", "how")+                if pref.get(k) is not None}+        keep["updatedAt"] = time.strftime("%Y-%m-%dT%H:%M:%S")+        SIGNIN_BROWSER_FILE.write_text(json.dumps(keep, indent=2), encoding="utf-8")+        return True+    except Exception:+        return False+++def forget_signin_browser() -> bool:+    try:+        SIGNIN_BROWSER_FILE.unlink()+        return True+    except FileNotFoundError:+        return True+    except Exception:+        return False+++def _launch_url_in_browser(pref: dict, url: str) -> bool:+    """Launch a SPECIFIC browser+profile (not the OS default) at url. Chromium browsers+    take --profile-directory + --new-window; a bare exe still opens its default profile.+    Returns True if the process spawned."""+    exe = pref.get("exe")+    if not exe or not os.path.exists(exe):+        return False+    cmd = [exe]+    prof = pref.get("profileDir")+    if prof:+        cmd.append(f"--profile-directory={prof}")+    if pref.get("newWindow", True):+        cmd.append("--new-window")+    cmd.append(url)+    try:+        subprocess.Popen(cmd, close_fds=True)+        return True+    except Exception:+        return False++# ── NEVER-CHARGE GUARANTEE (hard rule) ───────────────────────────────────────+# A user must NEVER be charged money — a card on file is only ever for Autodesk's+# identity verification. Two independent guarantees enforce this:+#   1. ALLOWLIST — the bridge calls ONLY Autodesk Data Management endpoints, which+#      are in APS's always-FREE API set. The paid APIs (Model Derivative, Design+#      Automation, Reality Capture, etc.) are NEVER called. Any path outside the+#      allowlist is refused before the request goes out.+#   2. METER + HARD CAP — even free APIs have monthly quotas; we count calls per+#      UTC month and FAIL CLOSED at a conservative cap, so a runaway loop can never+#      push past the free tier into billable overage.+# Data Management (/project/v1/, /data/v1/) AND OSS storage (/oss/v2/) are all in+# APS's always-FREE set — transferring your OWN Fusion Team hub files (download/+# upload) is included with the subscription, never billed. The paid APIs+# (Model Derivative, Automation, Reality Capture) are never in this list.+FREE_PATH_PREFIXES = ("/project/v1/", "/data/v1/", "/oss/v2/")+MONTHLY_CALL_CAP = 50000  # conservative; well under the DM free quota; fail-closed++_signin_lock = threading.Lock()+_signin_state = None  # {"verifier","state","server","thread","done","error","startedAt"}+++# ── Extension-free browser opening (issue #12) ───────────────────────────────+# ABE gained OS-level, EXTENSION-FREE verbs (nbrowser_open_os_window / nbrowser_os_windows):+# they open a URL in a REAL browser PROFILE without the Adom extension being installed in that+# Chrome/Edge. That is exactly the OAuth-consent case, so APS sign-in no longer dead-ends on a+# machine with no extension (Caleb, issue #12). The extension is still WORTH having - with it we+# can drive/see/screenshot the window instead of asking the user to click - so we upsell it.+_ABE_UPSELL = ("OPTIONAL, offer it: installing the Adom browser extension lets me DRIVE this "+               "sign-in instead of asking the user to click (fill, read the result, screenshot, "+               "clean up). ABE can install it for them automatically - it is just slow, roughly a "+               "5-minute AI-driven process. See the 'installing-the-extension' flow. Everything "+               "here works WITHOUT it; the extension only buys automation.")+++def _ad(verb: str, args: dict, timeout: int = 60) -> dict:+    """Call an AD verb from aps.py. Lazy-imports server (which imports us) so there is no+    circular import at module load. Never raises."""+    try:+        import server as _s+        return _s._ad_call(verb, args, timeout=timeout) or {}+    except Exception as e:+        return {"_adCallError": str(e)}+++def _abe_state() -> dict:+    """Probe ABE readiness so the response can say WHY a path was chosen, and whether the+    (optional) extension is present. Degrades to {'known': False} on any failure."""+    r = _ad("nbrowser_readiness", {}, timeout=30)+    if not isinstance(r, dict) or r.get("_adCallError") or "ready" not in r:+        return {"known": False,+                "note": "could not probe ABE (verb missing or CLI too old); the extension-free "+                        "path does not need it"}+    return {"known": True,+            "ready": r.get("ready"),+            "extensionConnected": r.get("extensionConnected"),+            "profiles": r.get("profiles") or [],+            "chromeInstalled": r.get("chromeInstalled"),+            "extensionStale": r.get("extensionStale"),+            "staleProfiles": r.get("staleProfiles") or []}+++def _open_os_window_extension_free(url: str, profile: str = None) -> dict:+    """Open `url` in the user's REAL browser profile with NO extension required.++    Returns {launched: bool, where: str, profile: str, error: str}. `launched` is intentionally+    generous: nbrowser_open_os_window returns ok:false when it cannot resolve the new window's+    hwnd within ~8s, but the browser usually DID open (the tab often groups into an existing+    window). For a consent flow, "the page is in front of the user" is what matters, so a fired+    launch counts.+    """+    if not profile:+        # reuse the Autodesk profile the user already picked for Fusion's own sign-in+        try:+            import server as _s+            profile = _s._remembered_signin_profile()+        except Exception:+            profile = None+    a = {"sessionId": "aps-signin-%d" % int(time.time()),+         "thread": "fusion-aps-signin",+         "purpose": "Autodesk APS consent",+         "url": url, "background": True}+    if profile:+        a["profile"] = profile+    # PREFER the extension window: nbrowser_open_window makes the tab AGENT-OWNED, and CDP only+    # drives tabs it owns (nbrowser_* refuses `not_owned` with no override). Owning it is what+    # lets us CLICK 'Allow' for the user instead of leaving a consent page sitting there - the+    # same pattern that finally completed the Fusion sign-in. Fall back to the extension-free+    # OS window when there is no extension (issue #12: it must still work with none installed).+    r = _ad("nbrowser_open_window", a, timeout=60)+    owned = isinstance(r, dict) and not r.get("_adCallError") and (r.get("ok") or r.get("sessionId"))+    if not owned:+        r = _ad("nbrowser_open_os_window", a, timeout=60)+    if not isinstance(r, dict) or r.get("_adCallError"):+        return {"launched": False, "profile": profile,+                "error": (r or {}).get("_adCallError") or "nbrowser_open_os_window unavailable"}+    launched = bool(r.get("ok") or r.get("hwnd") or r.get("sessionId")+                    or "Launch fired" in str(r.get("_hint", "")))+    if launched:+        # hand it to the bridge's janitor so a consent window is never left as desktop litter+        try:+            import server as _s+            _s._track_signin_window(a.get("sessionId"), a.get("profile"), kind="aps")+        except Exception:+            pass+    return {"launched": launched, "agentOwned": bool(owned),+            "where": r.get("displayName") or r.get("profile") or profile,+            "profile": r.get("profile") or profile,+            "hwnd": r.get("hwnd"),+            "extensionInstalled": r.get("extensionInstalled"),+            "error": None if launched else (str(r.get("error") or r.get("_hint") or "")[:200])}+++def _signin_setup_chain(opened: bool, abe: dict) -> list:+    """A chain the agent can follow MECHANICALLY (Caleb's ask), instead of a bare command that+    may not exist on the box."""+    if opened:+        return [{"step": "user_approves",+                 "do": "Tell the user the exact profile it opened in and ask them to click Approve."},+                {"step": "poll", "verb": "fusion_aps_status",+                 "until": "signedIn:true"}]+    chain = [{"step": "open_consent", "verb": "nbrowser_open_os_window",+              "args": {"sessionId": "<task id>", "thread": "<your thread>",+                       "purpose": "Autodesk APS consent", "profile": "chrome:<their-autodesk-email>",+                       "url": "<authUrl from this response>"},+              "note": "EXTENSION-FREE - works with no Adom extension installed. If this verb is "+                      "unknown, the adom-desktop CLI on this box is too old: update it (or have "+                      "the user paste authUrl into the right profile by hand)."},+             {"step": "user_approves",+              "do": "Ask the user to approve in that profile; without the extension we cannot click for them."},+             {"step": "poll", "verb": "fusion_aps_status", "until": "signedIn:true"}]+    if abe.get("known") and not abe.get("extensionConnected"):+        chain.append({"step": "optional_extension", "flow": "installing-the-extension",+                      "why": "lets the assistant DRIVE the sign-in instead of asking for clicks",+                      "cost": "~5 minutes, ABE automates it"})+    return chain+++# ── Config + token storage ───────────────────────────────────────────────────+def _read_json(path: Path) -> dict:+    try:+        return json.loads(path.read_text(encoding="utf-8"))+    except Exception:+        return {}+++def _write_json(path: Path, data: dict):+    APS_DIR.mkdir(parents=True, exist_ok=True)+    path.write_text(json.dumps(data, indent=2), encoding="utf-8")+++def get_client_id() -> str:+    return _read_json(CONFIG_FILE).get("client_id", "") or os.environ.get("FUSION_APS_CLIENT_ID", "")+++def set_client_id(client_id: str):+    cfg = _read_json(CONFIG_FILE)+    cfg["client_id"] = client_id.strip()+    _write_json(CONFIG_FILE, cfg)+++def _load_tokens() -> dict:+    return _read_json(TOKENS_FILE)+++def _save_tokens(tok: dict):+    _write_json(TOKENS_FILE, tok)+++# ── Usage meter (per UTC month; fail-closed cap) ─────────────────────────────+def _usage_month() -> str:+    return time.strftime("%Y-%m", time.gmtime())+++def _read_usage() -> dict:+    u = _read_json(USAGE_FILE)+    if u.get("month") != _usage_month():+        u = {"month": _usage_month(), "calls": 0}  # auto-reset each month+    return u+++def _bump_usage(n: int = 1) -> dict:+    with _usage_lock:  # parallel search calls share this+        u = _read_usage()+        u["calls"] = int(u.get("calls", 0)) + n+        _write_json(USAGE_FILE, u)+        return u+++def _cap_remaining() -> int:+    return max(0, MONTHLY_CALL_CAP - int(_read_usage().get("calls", 0)))+++# ── PKCE helpers ─────────────────────────────────────────────────────────────+def _pkce_pair():+    verifier = base64.urlsafe_b64encode(secrets.token_bytes(48)).rstrip(b"=").decode()+    challenge = base64.urlsafe_b64encode(+        hashlib.sha256(verifier.encode()).digest()+    ).rstrip(b"=").decode()+    return verifier, challenge+++# ── HTTP ─────────────────────────────────────────────────────────────────────+def _http(method: str, url: str, headers=None, data=None, timeout=30):+    """Return (status, json_or_text). Never raises on HTTP error — returns the body."""+    if isinstance(data, dict):+        data = urllib.parse.urlencode(data).encode()+    req = urllib.request.Request(url, data=data, headers=headers or {}, method=method)+    try:+        with urllib.request.urlopen(req, timeout=timeout) as resp:+            body = resp.read().decode("utf-8", "replace")+            return resp.status, _maybe_json(body)+    except urllib.error.HTTPError as e:+        body = e.read().decode("utf-8", "replace")+        return e.code, _maybe_json(body)+    except Exception as e:+        return 0, {"error": str(e)}+++def _maybe_json(text: str):+    try:+        return json.loads(text)+    except Exception:+        return text+++# ── Token lifecycle ──────────────────────────────────────────────────────────+def _exchange_code(code: str, verifier: str) -> dict:+    status, body = _http("POST", TOKEN_URL,+        headers={"Content-Type": "application/x-www-form-urlencoded"},+        data={+            "grant_type": "authorization_code",+            "code": code,+            "client_id": get_client_id(),+            "redirect_uri": _active_redirect_uri,  # must match the authorize request+            "code_verifier": verifier,+        })+    if status == 200 and isinstance(body, dict) and body.get("access_token"):+        body["obtained_at"] = int(time.time())+        body["expires_at"] = int(time.time()) + int(body.get("expires_in", 3600)) - 60+        _save_tokens(body)+        return {"ok": True}+    return {"ok": False, "status": status, "body": body}+++def _refresh() -> bool:+    tok = _load_tokens()+    rt = tok.get("refresh_token")+    if not rt:+        return False+    # IMPORTANT: do NOT send scope on refresh. A refresh may only narrow scope, not+    # broaden it — so passing the (now wider) SCOPES would make Autodesk reject any+    # token originally granted read-only. Omitting scope preserves whatever was+    # granted, so existing read sessions keep refreshing; write features just need a+    # fresh fusion_aps_signin to consent to the wider scope.+    status, body = _http("POST", TOKEN_URL,+        headers={"Content-Type": "application/x-www-form-urlencoded"},+        data={+            "grant_type": "refresh_token",+            "refresh_token": rt,+            "client_id": get_client_id(),+        })+    if status == 200 and isinstance(body, dict) and body.get("access_token"):+        body["obtained_at"] = int(time.time())+        body["expires_at"] = int(time.time()) + int(body.get("expires_in", 3600)) - 60+        if "refresh_token" not in body:+            body["refresh_token"] = rt+        _save_tokens(body)+        return True+    return False+++def _valid_access_token() -> str | None:+    tok = _load_tokens()+    if not tok.get("access_token"):+        return None+    if int(tok.get("expires_at", 0)) <= int(time.time()):+        if not _refresh():+            return None+        tok = _load_tokens()+    return tok.get("access_token")+++def _aps_get(path: str, query: dict = None):+    """Authenticated GET against APS. `path` is absolute-from-host or a full URL.++    Enforces the never-charge guarantee: free-API allowlist + monthly hard cap.+    """+    at = _valid_access_token()+    if not at:+        return None, {"error": "not_signed_in"}++    # Guarantee 1: only ever hit free Data Management endpoints.+    only_path = path if not path.startswith("http") else urllib.parse.urlparse(path).path+    if not any(only_path.startswith(p) for p in FREE_PATH_PREFIXES):+        return 0, {"error": "blocked_non_free_endpoint", "path": only_path,+                   "_hint": "Refused — the bridge only calls free Data Management endpoints "+                            "(/project/v1/, /data/v1/) so you are never charged."}++    # Guarantee 2: fail closed at the monthly cap (never blow past the free tier).+    if _cap_remaining() <= 0:+        return 0, {"error": "usage_cap_reached", "cap": MONTHLY_CALL_CAP,+                   "_hint": f"Monthly APS call cap ({MONTHLY_CALL_CAP}) reached — refusing further "+                            "calls so you are never charged. Resets at the start of next UTC month."}++    url = path if path.startswith("http") else f"{APS_BASE}{path}"+    if query:+        url += ("&" if "?" in url else "?") + urllib.parse.urlencode(query)+    _bump_usage(1)+    return _http("GET", url, headers={"Authorization": f"Bearer {at}"})+++# ── Sign-in (PKCE, browser + background callback listener) ────────────────────+class _CallbackHandler(BaseHTTPRequestHandler):+    def do_GET(self):+        parsed = urllib.parse.urlparse(self.path)+        if parsed.path != REDIRECT_PATH:+            self.send_response(404); self.end_headers(); return+        qs = urllib.parse.parse_qs(parsed.query)+        code = (qs.get("code") or [None])[0]+        state = (qs.get("state") or [None])[0]+        ok = False+        with _signin_lock:+            st = _signin_state+        if code and st and state == st["state"]:+            res = _exchange_code(code, st["verifier"])+            ok = res.get("ok", False)+            with _signin_lock:+                st["done"] = True+                st["error"] = None if ok else res+        html = (b"<html><body style='font-family:sans-serif;background:#111;color:#eee;"+                b"text-align:center;padding-top:80px'><h2>Fusion APS: "+                + (b"signed in &check;" if ok else b"sign-in failed")+                + b"</h2><p>You can close this tab and return to Adom.</p></body></html>")+        self.send_response(200)+        self.send_header("Content-Type", "text/html")+        self.end_headers()+        self.wfile.write(html)++    def log_message(self, *a):+        pass+++def start_signin(args: dict | None = None) -> dict:+    global _signin_state, _active_redirect_uri+    args = args or {}+    client_id = get_client_id()+    if not client_id:+        return {"success": False, "error": "No APS Client ID configured.",+                "errorCode": "aps_not_configured",+                "_hint": "Call fusion_aps_set_client_id {\"clientId\":\"...\"} first "+                         "(register a Desktop/PKCE app at https://aps.autodesk.com with "+                         "Data Management API + callbacks " + ", ".join(all_registered_callbacks()) + ")."}++    verifier, challenge = _pkce_pair()+    state = secrets.token_urlsafe(16)+    # Bind the FIRST free callback port from the registered set.+    server = None+    bound_port = None+    for port in REDIRECT_PORTS:+        try:+            server = HTTPServer(("127.0.0.1", port), _CallbackHandler)+            bound_port = port+            break+        except OSError:+            continue+    if server is None:+        return {"success": False,+                "error": f"All callback ports busy on this machine: {REDIRECT_PORTS}",+                "_hint": "Close whatever is holding these ports, or a sign-in is already in "+                         "progress. These are only bound for ~3 min during sign-in."}+    _active_redirect_uri = _redirect_uri(bound_port)++    with _signin_lock:+        _signin_state = {"verifier": verifier, "state": state, "server": server,+                         "done": False, "error": None, "startedAt": time.time()}++    def _serve():+        # Handle requests until the exchange completes or ~3 min elapses.+        server.timeout = 1+        deadline = time.time() + 180+        while time.time() < deadline:+            with _signin_lock:+                done = _signin_state and _signin_state["done"]+            if done:+                break+            server.handle_request()+        try:+            server.server_close()+        except Exception:+            pass++    threading.Thread(target=_serve, daemon=True).start()++    params = {+        "response_type": "code",+        "client_id": client_id,+        "redirect_uri": _active_redirect_uri,+        "scope": SCOPES,+        "code_challenge": challenge,+        "code_challenge_method": "S256",+        "state": state,+        # No prompt=login — reuse the user's existing Autodesk browser session so+        # sign-in is one-click (or zero-click if already consented), not a forced+        # re-login every time.+    }+    auth_url = AUTH_URL + "?" + urllib.parse.urlencode(params)++    # ── PROGRAMMATIC AUTH-001 SELF-HEAL (John 2026-07-14) ────────────────────────────────────────+    # Detect a broken APS app (lost its Data Management API PRODUCT) SERVER-SIDE, before opening any+    # browser, and hand back the exact ABE-driven recovery recipe. Without this, the AI opens a browser,+    # hits a raw AUTH-001 JSON error page, and has to reverse-engineer the fix (it once took an hour).+    if _probe_authorize_auth001(auth_url):+        try:+            server.server_close()+        except Exception:+            pass+        with _signin_lock:+            _signin_state = None+        return {"success": False,+                "error": "APS AUTH-001: the app's Client ID does not have access to the Data Management API product.",+                "errorCode": "aps_app_missing_product",+                "authUrl": auth_url,+                "appManagementUrl": "https://aps.autodesk.com/myapps/",+                "clientId": client_id,+                "recoverable": True,+                "_hint": _aps_auth001_recovery_hint(client_id)}++    # ── SMART BROWSER CHOICE (John, 2026-07-08: "power users have tons of browsers with tons+    #    of profiles ... cache what browser you used when you successfully logged in ... don't+    #    be lazy") ─────────────────────────────────────────────────────────────────────────+    # Priority: (1) a browser+profile passed in THIS call, (2) the one we REMEMBERED from the+    # last successful sign-in, (3) if neither AND the caller can drive the extension, open+    # NOTHING and tell it to open in the user's REAL browser (new window) via nbrowser_* — that+    # window holds the warm Autodesk/SSO session. Only fall back to the OS default browser when+    # explicitly allowed, because on a multi-browser machine the default is usually the WRONG+    # one (no session / wrong profile) and forces a needless fresh login.+    passed = None+    if args.get("exe"):+        passed = {"name": args.get("browser") or args.get("name"), "exe": args.get("exe"),+                  "profileDir": args.get("profileDir"), "newWindow": args.get("newWindow", True)}+    pref = passed or load_signin_browser()+    opened_via = None+    opened_pref = None+    ext_free = None      # result of the EXTENSION-FREE open, if we take that path+    abe = _abe_state()   # probed once, reported either way (issue #12)+    if pref and _launch_url_in_browser(pref, auth_url):+        opened_via = "remembered_browser" if not passed else "specified_browser"+        opened_pref = {k: pref.get(k) for k in ("name", "exe", "profileDir")}+        # A browser passed explicitly is now the remembered one (it's what the caller chose to+        # drive). A previously-remembered one is refreshed to keep its timestamp warm.+        save_signin_browser(pref)+    elif args.get("allowDefaultBrowser"):+        # Legacy fallback — only when the caller opts in (e.g. no extension available).+        try:+            webbrowser.open(auth_url)+            opened_via = "os_default_browser"+        except Exception:+            try:+                os.startfile(auth_url)  # noqa: Windows+                opened_via = "os_default_browser"+            except Exception:+                opened_via = None+    else:+        # EXTENSION-FREE open (issue #12, Caleb): we used to stop here and hand back a hint+        # telling the AI to run nbrowser_open_window - which REQUIRES the ABE extension. On a+        # box without it (or on a CLI too old to know the verb) that hint was un-followable and+        # the whole sign-in dead-ended. ABE now exposes nbrowser_open_os_window, which opens a+        # URL in a REAL browser PROFILE with NO extension installed - exactly the OAuth-consent+        # case. Try that before giving up.+        ext_free = _open_os_window_extension_free(auth_url, args.get("profile"))+        if ext_free.get("launched"):+            opened_via = "os_window_extension_free"+        else:+            opened_via = "none_use_extension"++    if opened_via in ("remembered_browser", "specified_browser"):+        _hint = (f"Opened the Autodesk consent in the REMEMBERED browser ({opened_pref.get('name') or 'cached'}"+                 f"{'/' + opened_pref['profileDir'] if opened_pref.get('profileDir') else ''}) — the one that "+                 "authed last time. A background listener on port "+                 f"{bound_port} captures the token once you approve. Poll fusion_aps_status until signedIn:true.")+    elif opened_via == "os_default_browser":+        _hint = ("Opened in the OS DEFAULT browser (fallback). On a multi-browser machine this may be the "+                 "wrong profile; prefer driving authUrl in the user's real browser via nbrowser_open_window "+                 "(new window), then call fusion_aps_set_browser to remember it. Poll fusion_aps_status.")+    elif opened_via == "os_window_extension_free":+        _hint = ("Opened the Autodesk consent in %s using the EXTENSION-FREE path "+                 "(nbrowser_open_os_window) - no Adom browser extension required. TELL THE USER which "+                 "profile it opened in (never just 'your browser') and that THEY need to click Approve, "+                 "because without the extension I cannot see or drive that window. A listener on port "+                 "%s captures the token once they approve. Poll fusion_aps_status until signedIn:true. "+                 "%s" % (ext_free.get("where") or "the user's browser profile", bound_port,+                         _ABE_UPSELL))+    else:+        _hint = ("Could not open a browser for you. No REMEMBERED Autodesk browser, and the EXTENSION-FREE "+                 "open (nbrowser_open_os_window) did not fire%s. DO THIS: run the setupChain in this "+                 "response in order. Simplest manual fallback - have the USER paste authUrl into the "+                 "browser profile their Autodesk account lives in. A listener on port "+                 "%s captures the token once they approve; poll fusion_aps_status until signedIn:true. %s"+                 % ((": " + str(ext_free.get("error"))[:120]) if ext_free and ext_free.get("error") else "",+                    bound_port, _ABE_UPSELL))++    ok_open = bool(opened_via and opened_via != "none_use_extension")+    return {+        "success": True,+        "output": ("Autodesk sign-in started. " + (+            "Approve access in the opened browser, then call fusion_aps_status."+            if ok_open+            else "Open authUrl in the user's real browser (new window) to approve.")),+        "authUrl": auth_url,+        "redirectUri": _active_redirect_uri,+        "openedVia": opened_via,+        "openedBrowser": opened_pref,+        # Extension-free open no longer NEEDS the extension - keep the old flag truthful for+        # existing callers, but only assert it when we genuinely could not open anything.+        "needsExtensionOpen": opened_via == "none_use_extension",+        "extensionFree": ext_free,+        # Caleb's asks (issue #12): a structured code + a chain the agent can follow mechanically,+        # instead of a raw command that may not exist on this box.+        "errorCode": None if ok_open else "browser_open_failed",+        "abe": abe,+        "setupChain": _signin_setup_chain(ok_open, abe),+        "_hint": _hint,+    }+++# ── Verb handlers ────────────────────────────────────────────────────────────+def handle_status(args: dict) -> dict:+    # NOTE: AD's relay only forwards output/data/success/error/_hint to the+    # cloud caller — every structured field MUST live under `data`.+    client_id = get_client_id()+    tok = _load_tokens()+    has_at = bool(tok.get("access_token"))+    live = has_at and int(tok.get("expires_at", 0)) > int(time.time())+    # signedIn MUST mean "I can actually call APS right now", not "a token file exists".+    # It used to be bool(has_at), so status happily reported signedIn:true while every search+    # died with APS token_expired - and fusion_readiness repeated that lie to the user+    # (caught live 2026-07-22). _valid_access_token() refreshes when possible, so this is the+    # honest signal: usable == live now, or refreshable now.+    usable = bool(live)+    if has_at and not live:+        try:+            usable = bool(_valid_access_token())+        except Exception:+            usable = False+    refresh_failed = bool(has_at and not usable)+    with _signin_lock:+        pending = bool(_signin_state and not _signin_state["done"]+                       and time.time() - _signin_state["startedAt"] < 180)+    usage = _read_usage()+    data = {+        "configured": bool(client_id),+        "signedIn": bool(usable),          # usable NOW (refreshed if needed), not merely present+        "hasStoredToken": bool(has_at),    # a token file exists (may be dead)+        "refreshFailed": refresh_failed,   # stored token is dead and could not be refreshed+        "tokenLive": bool(live),+        "tokenExpiresAt": tok.get("expires_at"),+        "scope": tok.get("scope", SCOPES),+        "signinPending": pending,+        "callbackUrls": all_registered_callbacks(),+        # Never-charge meter — the AI-driven setup watches this.+        "usageMonth": usage.get("month"),+        "callsThisMonth": int(usage.get("calls", 0)),+        "monthlyCap": MONTHLY_CALL_CAP,+        "capRemaining": _cap_remaining(),+        "freeEndpointsOnly": list(FREE_PATH_PREFIXES),+        "neverCharge": True,+    }+    if not client_id:+        hint = ("Not configured. Register a Desktop/PKCE app at https://aps.autodesk.com "+                "(enable Data Management API, set callbacks " + ", ".join(all_registered_callbacks())+                + "), then fusion_aps_set_client_id {\"clientId\":\"...\"} and fusion_aps_signin.")+        summary = "APS not configured"+    elif not has_at:+        hint = "Configured but not signed in. Call fusion_aps_signin (opens browser)."+        summary = "configured, not signed in"+    elif not live:+        hint = "Token expired and refresh failed. Call fusion_aps_signin again."+        summary = "signed in, token expired"+    else:+        hint = "Ready. Use fusion_aps_search {\"query\":\"...\"}."+        summary = "ready"+    return {"success": True, "output": summary, "data": data, "_hint": hint}+++def handle_set_client_id(args: dict) -> dict:+    cid = (args.get("clientId") or args.get("client_id") or "").strip()+    if not cid:+        return {"success": False, "error": "Missing clientId."}+    set_client_id(cid)+    return {"success": True,+            "output": f"Saved APS Client ID ({cid[:6]}...). Now call fusion_aps_signin.",+            "data": {"configured": True}}+++def handle_signin(args: dict) -> dict:+    res = start_signin(args or {})+    # Move custom fields under data so the relay forwards them.+    if res.get("success"):+        res["data"] = {"authUrl": res.pop("authUrl", None),+                       "redirectUri": res.pop("redirectUri", None),+                       "openedVia": res.pop("openedVia", None),+                       "openedBrowser": res.pop("openedBrowser", None),+                       "needsExtensionOpen": res.pop("needsExtensionOpen", False)}+    return res+++def handle_set_browser(args: dict) -> dict:+    """Remember the browser+profile that successfully authed to Autodesk, so every later+    fusion_aps_signin reuses it instead of the OS default. Call this right after a driven+    sign-in succeeds (with the browser you opened authUrl in). Fields: name, exe, profileDir,+    newWindow. `exe` is the browser binary on the host; profileDir is e.g. 'Default'/'Profile 2'."""+    exe = (args.get("exe") or "").strip()+    pref = {"name": args.get("name") or args.get("browser"), "exe": exe or None,+            "profileDir": args.get("profileDir"), "newWindow": args.get("newWindow", True),+            "how": args.get("how") or ("extension" if not exe else "launch")}+    if not exe and pref["how"] != "extension":+        return {"success": False, "error": "Provide exe (browser binary path) or how:'extension'.",+                "_hint": "e.g. {name:'Edge', exe:'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe', profileDir:'Default'}"}+    ok = save_signin_browser(pref)+    return {"success": ok, "output": f"Remembered Autodesk sign-in browser: {pref.get('name') or exe or pref['how']}.",+            "data": {"saved": ok, "browser": load_signin_browser()}}+++def handle_get_browser(args: dict) -> dict:+    """Show the remembered Autodesk sign-in browser (None if not set yet)."""+    pref = load_signin_browser()+    return {"success": True, "output": ("Remembered: " + (pref.get("name") or pref.get("exe") or pref.get("how"))+            if pref else "No Autodesk sign-in browser remembered yet."),+            "data": {"browser": pref}}+++def handle_forget_browser(args: dict) -> dict:+    """Forget the remembered browser (next sign-in re-detects / uses the extension)."""+    ok = forget_signin_browser()+    return {"success": ok, "output": "Forgot the remembered Autodesk sign-in browser." if ok else "Could not clear it.",+            "data": {"cleared": ok}}+++def handle_get(args: dict) -> dict:+    """Raw authenticated GET — dev/verify helper for nailing the APS grammar."""+    path = args.get("path")+    if not path:+        return {"success": False, "error": "Missing path."}+    status, body = _aps_get(path, args.get("query"))+    return {"success": 200 <= (status or 0) < 300,+            "output": f"HTTP {status}",+            "data": {"httpStatus": status, "body": body}}+++def _list_hubs():+    status, body = _aps_get("/project/v1/hubs")+    if status != 200 or not isinstance(body, dict):+        return [], (status, body)+    return body.get("data", []), None+++def _list_projects(hub_id):+    status, body = _aps_get(f"/project/v1/hubs/{hub_id}/projects")+    if status != 200 or not isinstance(body, dict):+        return []+    return body.get("data", [])+++def _top_folders(hub_id, project_id):+    status, body = _aps_get(f"/project/v1/hubs/{hub_id}/projects/{project_id}/topFolders")+    if status != 200 or not isinstance(body, dict):+        return []+    return body.get("data", [])+++def _folder_search(project_id, folder_id, query, limit):+    """Recursive name search within a folder.++    APS's `:search` endpoint is the server-side recursive INDEX (returns all+    descendant items in a few paged calls — vastly faster than the add-in walk).+    Its server-side `filter[attributes.displayName]` matching proved unreliable+    (returned 0 for known files), so we page through the index and filter+    displayName CLIENT-SIDE (case-insensitive substring) — robust + still fast.+    """+    ql = query.lower()+    matches, seen = [], set()++    def _take(it):+        iid = it.get("id")+        if iid in seen:+            return False+        name = (it.get("attributes", {}) or {}).get("displayName", "") or ""+        if ql in name.lower():+            seen.add(iid)+            matches.append(it)+        return len(matches) >= limit++    # Pass 1 — the folder's DIRECT contents. :search only recurses subfolders, so+    # items sitting in the top folder itself (e.g. a design straight in "Main")+    # would otherwise be missed.+    status, body = _aps_get(f"/data/v1/projects/{project_id}/folders/{folder_id}/contents",+                            {"page[limit]": 200})+    if status == 200 and isinstance(body, dict):+        for it in body.get("data", []):+            if it.get("type") == "items" and _take(it):+                return matches, None++    # Pass 2 — the recursive server index (fast, free), paged. Filter client-side+    # (the server-side displayName filter is unreliable — returns 0 for known files).+    url, next_q = f"/data/v1/projects/{project_id}/folders/{folder_id}/search", {"page[limit]": 200}+    for _ in range(25):+        status, body = _aps_get(url, next_q)+        if status != 200 or not isinstance(body, dict):+            return matches, (None if matches else (status, body))+        for it in body.get("data", []):+            if _take(it):+                return matches, None+        nxt = (body.get("links", {}) or {}).get("next", {})+        nxt_href = nxt.get("href") if isinstance(nxt, dict) else nxt+        if not nxt_href:+            break+        url, next_q = nxt_href, None+    return matches, None+++def handle_search(args: dict) -> dict:+    query = (args.get("query") or "").strip()+    if not query:+        return {"success": False, "error": "Missing query."}+    if not _valid_access_token():+        return {"success": False, "error": "Not signed in to APS.",+                "errorCode": "aps_not_signed_in",+                "_hint": APS_REQUIRED_HINT}+    limit = int(args.get("limit", 50))+    hub_filter = args.get("hubId")+    project_filter = args.get("projectId")++    hubs, err = _list_hubs()+    if err:+        return {"success": False, "error": "APS hubs request failed.",+                "data": {"httpStatus": err[0], "body": err[1]},+                "_hint": "Token may lack data:read scope or the app isn't Data-Management-enabled."}++    # Build the (hub, project, folder) task list, then search projects IN PARALLEL.+    scanned = {"hubs": 0, "projects": 0, "folders": 0}+    tasks = []+    for hub in hubs:+        hub_id = hub.get("id")+        if hub_filter and hub_id != hub_filter:+            continue+        scanned["hubs"] += 1+        projects = _list_projects(hub_id)+        if project_filter:+            projects = [p for p in projects if p.get("id") == project_filter] or \+                       [{"id": project_filter, "attributes": {"name": project_filter}}]+        for proj in projects:+            pid = proj.get("id")+            pname = (proj.get("attributes", {}) or {}).get("name", "")+            scanned["projects"] += 1+            for folder in _top_folders(hub_id, pid):+                scanned["folders"] += 1+                tasks.append((hub_id, pid, pname, folder.get("id")))++    def _scan(task):+        hub_id, pid, pname, fid = task+        hits, _ = _folder_search(pid, fid, query, limit)+        out = []+        for h in hits:+            a = h.get("attributes", {}) or {}+            out.append({"name": a.get("displayName"), "type": h.get("type"), "id": h.get("id"),+                        "hubId": hub_id, "projectId": pid, "projectName": pname,+                        "lastModified": a.get("lastModifiedTime")})+        return out++    results, seen = [], set()+    with ThreadPoolExecutor(max_workers=12) as pool:+        for out in pool.map(_scan, tasks):+            for r in out:+                if r["id"] in seen:+                    continue+                seen.add(r["id"])+                results.append(r)++    results.sort(key=lambda r: (r.get("lastModified") or ""), reverse=True)+    return {+        "success": True,+        "output": f"{len(results)} match(es) for '{query}'",+        "data": {+            "query": query,+            "count": len(results),+            "results": results[:limit],+            "scanned": scanned,+        },+        "_hint": f"Found {len(results)} match(es) via the APS server index across "+                 f"{scanned['projects']} project(s), newest first. Pass projectId to scope to "+                 "one project (faster). Use fusion_aps_open to open a hit in Fusion.",+    }+++def find_one(query: str) -> dict | None:+    """Best single match for a query (newest) — used by fusion_aps_open."""+    res = handle_search({"query": query, "limit": 5})+    rs = res.get("data", {}).get("results", [])+    return rs[0] if rs else None+++def handle_browse(args: dict) -> dict:+    """Browse the cloud without launching Fusion: hubs+projects → top folders → contents."""+    if not _valid_access_token():+        return {"success": False, "error": "Not signed in to APS.", "errorCode": "aps_not_signed_in",+                "_hint": APS_REQUIRED_HINT}+    hub_id = args.get("hubId")+    project_id = args.get("projectId")+    folder_id = args.get("folderId")++    if project_id and folder_id:+        s, b = _aps_get(f"/data/v1/projects/{project_id}/folders/{folder_id}/contents", {"page[limit]": 200})+        items = [{"name": (x.get("attributes", {}) or {}).get("displayName") or (x.get("attributes", {}) or {}).get("name"),+                  "type": x.get("type"), "id": x.get("id")} for x in (b.get("data", []) if isinstance(b, dict) else [])]+        return {"success": s == 200, "output": f"{len(items)} item(s)",+                "data": {"level": "folder", "projectId": project_id, "folderId": folder_id, "items": items}}++    if project_id:+        if not hub_id:+            hubs, _ = _list_hubs()+            hub_id = hubs[0].get("id") if hubs else None+        folders = _top_folders(hub_id, project_id)+        items = [{"name": (f.get("attributes", {}) or {}).get("name"), "type": "folder", "id": f.get("id")}+                 for f in folders]+        return {"success": True, "output": f"{len(items)} top folder(s)",+                "data": {"level": "project", "hubId": hub_id, "projectId": project_id, "items": items}}++    hubs, err = _list_hubs()+    if err:+        return {"success": False, "error": "APS hubs request failed.", "data": {"body": err[1]}}+    out = []+    for h in hubs:+        hid = h.get("id")+        if hub_id and hid != hub_id:+            continue+        projs = _list_projects(hid)+        out.append({"hub": (h.get("attributes", {}) or {}).get("name"), "hubId": hid,+                    "projects": [{"name": (p.get("attributes", {}) or {}).get("name"), "id": p.get("id")} for p in projs]})+    nprej = sum(len(x["projects"]) for x in out)+    return {"success": True, "output": f"{len(out)} hub(s), {nprej} project(s)",+            "data": {"level": "hubs", "hubs": out}}+++def handle_recent(args: dict) -> dict:+    """Most-recently-modified files across the team hub (or one project). Reuses the+    parallel index scan with a match-all filter, then sorts by lastModifiedTime."""+    if not _valid_access_token():+        return {"success": False, "error": "Not signed in to APS.", "errorCode": "aps_not_signed_in",+                "_hint": APS_REQUIRED_HINT}+    limit = int(args.get("limit", 25))+    hub_filter = args.get("hubId")+    project_filter = args.get("projectId")+    hubs, err = _list_hubs()+    if err:+        return {"success": False, "error": "APS hubs request failed.", "data": {"body": err[1]}}+    tasks = []+    for hub in hubs:+        hid = hub.get("id")+        if hub_filter and hid != hub_filter:+            continue+        projects = _list_projects(hid)+        if project_filter:+            projects = [p for p in projects if p.get("id") == project_filter] or \+                       [{"id": project_filter, "attributes": {"name": project_filter}}]+        for proj in projects:+            pid = proj.get("id")+            pname = (proj.get("attributes", {}) or {}).get("name", "")+            for f in _top_folders(hid, pid):+                tasks.append((pid, pname, f.get("id")))++    def _scan(t):+        pid, pname, fid = t+        hits, _ = _folder_search(pid, fid, "", 200)  # "" matches everything+        out = []+        for h in hits:+            a = h.get("attributes", {}) or {}+            out.append({"name": a.get("displayName"), "type": h.get("type"), "id": h.get("id"),+                        "projectId": pid, "projectName": pname, "lastModified": a.get("lastModifiedTime")})+        return out++    items, seen = [], set()+    with ThreadPoolExecutor(max_workers=12) as pool:+        for out in pool.map(_scan, tasks):+            for r in out:+                if r["id"] in seen:+                    continue+                seen.add(r["id"])+                items.append(r)+    items = [i for i in items if i.get("lastModified")]+    items.sort(key=lambda r: r["lastModified"], reverse=True)+    items = items[:limit]+    return {"success": True, "output": f"{len(items)} recent file(s)",+            "data": {"count": len(items), "results": items},+            "_hint": "Most-recently-modified designs across the team hub, newest first."}+++def handle_file_info(args: dict) -> dict:+    """Version history + metadata for a file: who last changed it, when, how many versions."""+    if not _valid_access_token():+        return {"success": False, "error": "Not signed in to APS.", "errorCode": "aps_not_signed_in",+                "_hint": APS_REQUIRED_HINT}+    project_id = args.get("projectId")+    urn = args.get("urn")+    name = args.get("name")+    query = (args.get("query") or "").strip()+    if query and not (project_id and urn):+        m = find_one(query)+        if not m:+            return {"success": False, "error": f"No cloud file matching '{query}'."}+        project_id, urn, name = m.get("projectId"), m.get("id"), m.get("name")+    if not (project_id and urn):+        return {"success": False, "error": "Provide query, or projectId + urn."}++    # Derive the item (lineage) urn from a version urn (vf.<base>?version=N).+    raw = urn.split("?")[0]+    item_urn = urn+    if "fs.file:vf." in raw:+        item_urn = "urn:adsk.wipprod:dm.lineage:" + raw.split("fs.file:vf.")[-1]+    enc = urllib.parse.quote(item_urn, safe="")+    s, b = _aps_get(f"/data/v1/projects/{project_id}/items/{enc}/versions")+    if s != 200 or not isinstance(b, dict):+        return {"success": False, "error": "Could not fetch versions.",+                "data": {"httpStatus": s, "body": b, "itemUrn": item_urn}}+    versions = []+    for v in b.get("data", []):+        a = v.get("attributes", {}) or {}+        versions.append({+            "versionNumber": a.get("versionNumber"),+            "lastModifiedTime": a.get("lastModifiedTime"),+            "lastModifiedUserName": a.get("lastModifiedUserName"),+            "createTime": a.get("createTime"),+            "createUserName": a.get("createUserName"),+            "storageSize": a.get("storageSize"),+        })+    versions.sort(key=lambda x: (x.get("versionNumber") or 0), reverse=True)+    tip = versions[0] if versions else {}+    return {+        "success": True,+        "output": f"{name or item_urn}: {len(versions)} version(s), last by {tip.get('lastModifiedUserName')}",+        "data": {"name": name, "projectId": project_id, "itemUrn": item_urn,+                 "versionCount": len(versions), "tip": tip, "versions": versions[:20]},+        "_hint": "Version history newest-first; tip = current version (who/when/size).",+    }+++# ── Free Data Management writes + file transfer ──────────────────────────────+# Everything below stays within the user's OWN Fusion Team hub. Data Management+# writes (folders/items/versions) and OSS storage transfer (download/upload) are+# in APS's always-FREE set, so the never-charge guarantee still holds (the gating+# in _aps_send mirrors _aps_get). Writes need data:write/data:create scope, so a+# user signed in under the old read-only scope must fusion_aps_signin once more.+JSONAPI = "application/vnd.api+json"+++def _aps_send(method: str, path: str, json_body=None, content_type=JSONAPI, timeout=120):+    """Authenticated POST/PATCH/PUT with the SAME never-charge gating as _aps_get."""+    at = _valid_access_token()+    if not at:+        return None, {"error": "not_signed_in"}+    only_path = path if not path.startswith("http") else urllib.parse.urlparse(path).path+    if not any(only_path.startswith(p) for p in FREE_PATH_PREFIXES):+        return 0, {"error": "blocked_non_free_endpoint", "path": only_path,+                   "_hint": "Refused — only free Data Management / OSS storage endpoints are "+                            "allowed, so you are never charged."}+    if _cap_remaining() <= 0:+        return 0, {"error": "usage_cap_reached", "cap": MONTHLY_CALL_CAP}+    url = path if path.startswith("http") else f"{APS_BASE}{path}"+    headers = {"Authorization": f"Bearer {at}"}+    data = None+    if json_body is not None:+        data = json.dumps(json_body).encode()+        headers["Content-Type"] = content_type+    _bump_usage(1)+    return _http(method, url, headers=headers, data=data, timeout=timeout)+++def _http_bytes(method: str, url: str, data=None, headers=None, timeout=300):+    """Raw binary HTTP (presigned S3 up/download) — _http decodes text, which would+    corrupt binary, so transfers use this. Returns (status, bytes)."""+    req = urllib.request.Request(url, data=data, headers=headers or {}, method=method)+    try:+        with urllib.request.urlopen(req, timeout=timeout) as resp:+            return resp.status, resp.read()+    except urllib.error.HTTPError as e:+        return e.code, e.read()+    except Exception as e:+        return 0, str(e).encode()+++def _lineage_urn(urn: str) -> str:+    raw = urn.split("?")[0]+    if "fs.file:vf." in raw:+        return "urn:adsk.wipprod:dm.lineage:" + raw.split("fs.file:vf.")[-1]+    return urn+++def _tip_version_urn(project_id: str, urn: str):+    """Given a version OR lineage urn, return a concrete version urn (tip if lineage)."""+    if "?version=" in urn or "fs.file:vf." in urn.split("?")[0]:+        return urn, None+    enc = urllib.parse.quote(_lineage_urn(urn), safe="")+    s, b = _aps_get(f"/data/v1/projects/{project_id}/items/{enc}")+    if s != 200 or not isinstance(b, dict):+        return None, (s, b)+    tip = (((b.get("data") or {}).get("relationships") or {}).get("tip") or {}).get("data") or {}+    return tip.get("id"), None+++def _storage_of_version(project_id: str, version_urn: str):+    enc = urllib.parse.quote(version_urn, safe="")+    s, b = _aps_get(f"/data/v1/projects/{project_id}/versions/{enc}")+    if s != 200 or not isinstance(b, dict):+        return None, None, (s, b)+    d = b.get("data") or {}+    storage = (((d.get("relationships") or {}).get("storage") or {}).get("data") or {}).get("id")+    name = (d.get("attributes") or {}).get("name")+    return storage, name, None+++def _parse_oss(storage_urn: str):+    # urn:adsk.objects:os.object:<bucketKey>/<objectKey>+    tail = storage_urn.split("os.object:", 1)[-1]+    bucket, _, obj = tail.partition("/")+    return bucket, obj+++def handle_versions(args: dict) -> dict:+    """Full version history of a file (every version, uncapped): who/when/size per version."""+    info = handle_file_info(args)+    if not info.get("success"):+        return info+    d = info["data"]+    project_id, item_urn = d["projectId"], d["itemUrn"]+    enc = urllib.parse.quote(item_urn, safe="")+    s, b = _aps_get(f"/data/v1/projects/{project_id}/items/{enc}/versions", {"page[limit]": 200})+    versions = []+    for v in (b.get("data", []) if isinstance(b, dict) else []):+        a = v.get("attributes", {}) or {}+        versions.append({"versionNumber": a.get("versionNumber"), "id": v.get("id"),+                         "lastModifiedTime": a.get("lastModifiedTime"),+                         "lastModifiedUserName": a.get("lastModifiedUserName"),+                         "createTime": a.get("createTime"), "createUserName": a.get("createUserName"),+                         "storageSize": a.get("storageSize")})+    versions.sort(key=lambda x: (x.get("versionNumber") or 0), reverse=True)+    return {"success": True, "output": f"{d.get('name') or item_urn}: {len(versions)} version(s)",+            "data": {"name": d.get("name"), "projectId": project_id, "itemUrn": item_urn,+                     "versionCount": len(versions), "versions": versions},+            "_hint": "Complete version history, newest-first."}+++def handle_download(args: dict) -> dict:+    """Download a cloud file to the local machine (no Fusion needed).+    args: query | (projectId + urn); optional saveDir, fileName."""+    if not _valid_access_token():+        return {"success": False, "error": "Not signed in to APS.", "errorCode": "aps_not_signed_in",+                "_hint": APS_REQUIRED_HINT}+    project_id, urn, name = args.get("projectId"), args.get("urn"), args.get("name")+    query = (args.get("query") or "").strip()+    if query and not (project_id and urn):+        m = find_one(query)+        if not m:+            return {"success": False, "error": f"No cloud file matching '{query}'."}+        project_id, urn, name = m.get("projectId"), m.get("id"), m.get("name")+    if not (project_id and urn):+        return {"success": False, "error": "Provide query, or projectId + urn."}++    version_urn, err = _tip_version_urn(project_id, urn)+    if not version_urn:+        return {"success": False, "error": "Could not resolve a version.", "data": {"detail": err}}+    storage_urn, vname, err = _storage_of_version(project_id, version_urn)+    if not storage_urn:+        return {"success": False, "error": "Could not find storage for this version.",+                "data": {"detail": err}}+    bucket, obj = _parse_oss(storage_urn)+    s, b = _aps_get(f"/oss/v2/buckets/{bucket}/objects/{urllib.parse.quote(obj, safe='')}/signeds3download")+    if s != 200 or not isinstance(b, dict) or not b.get("url"):+        return {"success": False, "error": "Could not get a download URL.",+                "data": {"httpStatus": s, "body": b}}++    save_dir = args.get("saveDir") or str(Path(os.path.expanduser("~")) / "Downloads")+    fname = args.get("fileName") or vname or name or "download.bin"+    Path(save_dir).mkdir(parents=True, exist_ok=True)+    out_path = str(Path(save_dir) / fname)+    st, data = _http_bytes("GET", b["url"])+    if st != 200:+        return {"success": False, "error": f"Download failed (HTTP {st}).",+                "data": {"bytes": len(data)}}+    with open(out_path, "wb") as fh:+        fh.write(data)+    return {"success": True, "output": f"Downloaded {fname} ({len(data):,} bytes) to {out_path}",+            "data": {"path": out_path, "bytes": len(data), "name": fname, "version": version_urn},+            "_hint": "Saved to the local machine; opening in Fusion is a separate step (fusion_aps_open)."}+++def handle_create_folder(args: dict) -> dict:+    """Create a subfolder in a project. args: projectId, parentFolderId, name."""+    if not _valid_access_token():+        return {"success": False, "error": "Not signed in to APS.", "errorCode": "aps_not_signed_in",+                "_hint": APS_REQUIRED_HINT}+    project_id = args.get("projectId")+    parent = args.get("parentFolderId") or args.get("folderId")+    fname = (args.get("name") or "").strip()+    if not (project_id and parent and fname):+        return {"success": False, "error": "Provide projectId, parentFolderId, name."}+    body = {"jsonapi": {"version": "1.0"},+            "data": {"type": "folders",+                     "attributes": {"name": fname,+                                    "extension": {"type": "folders:autodesk.core:Folder", "version": "1.0"}},+                     "relationships": {"parent": {"data": {"type": "folders", "id": parent}}}}}+    s, b = _aps_send("POST", f"/data/v1/projects/{project_id}/folders", body)+    if s not in (200, 201) or not isinstance(b, dict):+        return {"success": False, "error": "Create folder failed.",+                "data": {"httpStatus": s, "body": b},+                "_hint": "HTTP 403 = sign-in lacks data:write/data:create (fusion_aps_signin again). "+                         "409 = a folder with that name already exists here."}+    fid = (b.get("data") or {}).get("id")+    return {"success": True, "output": f"Created folder '{fname}'",+            "data": {"folderId": fid, "name": fname, "projectId": project_id}}+++def handle_upload(args: dict) -> dict:+    """Upload a local file as a NEW cloud file. args: projectId, folderId, localPath; opt fileName."""+    if not _valid_access_token():+        return {"success": False, "error": "Not signed in to APS.", "errorCode": "aps_not_signed_in",+                "_hint": APS_REQUIRED_HINT}+    project_id, folder_id, local = args.get("projectId"), args.get("folderId"), args.get("localPath")+    if not (project_id and folder_id and local):+        return {"success": False, "error": "Provide projectId, folderId, localPath."}+    # FOLDER HYGIENE: never dump loose files into a shared project ROOT (see fusion-cloud-hygiene).+    _KNOWN_ROOT_FOLDERS = {"urn:adsk.wipprod:fs.folder:co.jyO4vxQXR6S9zFpTQWnZAg"}+    if folder_id in _KNOWN_ROOT_FOLDERS:+        return {"success": False, "errorCode": "refused_root_upload",+                "error": "REFUSED: that folderId is a shared project ROOT - the bridge never writes "+                         "loose files there (it clutters the team's cloud).",+                "_hint": "Create/choose a real subfolder first (fusion_aps_create_folder under an "+                         "'Adom AI Workspace' folder), or just call fusion_make_3d_package / "+                         "fusion_build_library_3d, which now default to a non-root workspace folder. "+                         "See the fusion-cloud-hygiene skill."}+    if not os.path.isfile(local):+        return {"success": False, "error": f"Local file not found: {local}"}+    fname = args.get("fileName") or os.path.basename(local)+    data = open(local, "rb").read()++    # 1. Reserve a storage object in the target folder.+    sbody = {"jsonapi": {"version": "1.0"},+             "data": {"type": "objects", "attributes": {"name": fname},+                      "relationships": {"target": {"data": {"type": "folders", "id": folder_id}}}}}+    s, b = _aps_send("POST", f"/data/v1/projects/{project_id}/storage", sbody)+    if s not in (200, 201) or not isinstance(b, dict):+        return {"success": False, "error": "Storage reservation failed.",+                "data": {"httpStatus": s, "body": b},+                "_hint": "HTTP 403 = sign-in lacks data:write/data:create — fusion_aps_signin again."}+    storage_urn = (b.get("data") or {}).get("id")+    bucket, obj = _parse_oss(storage_urn)+    objenc = urllib.parse.quote(obj, safe="")++    # 2. Get a signed S3 upload URL, 3. PUT the bytes, 4. complete the upload.+    s, b = _aps_get(f"/oss/v2/buckets/{bucket}/objects/{objenc}/signeds3upload")+    if s != 200 or not isinstance(b, dict) or not b.get("urls"):+        return {"success": False, "error": "Could not get an upload URL.", "data": {"httpStatus": s, "body": b}}+    upload_key, put_url = b.get("uploadKey"), b["urls"][0]+    st, _ = _http_bytes("PUT", put_url, data=data, headers={"Content-Type": "application/octet-stream"})+    if st not in (200, 201):+        return {"success": False, "error": f"S3 upload PUT failed (HTTP {st})."}+    s, b = _aps_send("POST", f"/oss/v2/buckets/{bucket}/objects/{objenc}/signeds3upload",+                     {"uploadKey": upload_key}, content_type="application/json")+    if s not in (200, 201, 202):+        return {"success": False, "error": "Upload completion failed.", "data": {"httpStatus": s, "body": b}}++    # 5. Create the item (new file, version 1) pointing at the uploaded object.+    ibody = {"jsonapi": {"version": "1.0"},+             "data": {"type": "items",+                      "attributes": {"displayName": fname,+                                     "extension": {"type": "items:autodesk.core:File", "version": "1.0"}},+                      "relationships": {"tip": {"data": {"type": "versions", "id": "1"}},+                                        "parent": {"data": {"type": "folders", "id": folder_id}}}},+             "included": [{"type": "versions", "id": "1",+                           "attributes": {"name": fname,+                                          "extension": {"type": "versions:autodesk.core:File", "version": "1.0"}},+                           "relationships": {"storage": {"data": {"type": "objects", "id": storage_urn}}}}]}+    s, b = _aps_send("POST", f"/data/v1/projects/{project_id}/items", ibody)+    if s not in (200, 201) or not isinstance(b, dict):+        return {"success": False,+                "error": "Create item failed (this verb uploads NEW files; the name may already exist).",+                "data": {"httpStatus": s, "body": b}}+    item_id = (b.get("data") or {}).get("id")+    return {"success": True, "output": f"Uploaded '{fname}' ({len(data):,} bytes) as a new cloud file.",+            "data": {"itemUrn": item_id, "name": fname, "bytes": len(data),+                     "projectId": project_id, "folderId": folder_id}}+++# Command-name -> handler (invoked as fusion_aps_* from the CLI).+HANDLERS = {+    "aps_status": handle_status,+    "aps_set_client_id": handle_set_client_id,+    "aps_signin": handle_signin,+    "aps_search": handle_search,+    "aps_browse": handle_browse,+    "aps_recent": handle_recent,+    "aps_file_info": handle_file_info,+    "aps_versions": handle_versions,+    "aps_download": handle_download,+    "aps_create_folder": handle_create_folder,+    "aps_upload": handle_upload,+    "aps_get": handle_get,+}
bridge.jsonadded+190
@@ -0,0 +1,190 @@+{+  "manifest_version": 1,+  "name": "fusion360",+  "displayName": "Autodesk Fusion 360",+  "version": "1.8.3",+  "description": "Drive Autodesk Fusion 360 from the cloud: launch Fusion, electronics board layout, design rules, exports (STEP/IGES/STL/3MF/USDZ/OBJ/DXF/DWG/Gerbers/BOM/CPL), fast APS server-indexed cloud search plus browse/recent/file-info/versions, cloud file download/upload and folder creation, and in-app parametric modeling (fusion_run_modeling_script). Never-charge: APS calls are capped to the free tier.",+  "homepage": "https://wiki.adom.inc/adom/adom-desktop-fusion-bridge-macos",+  "author": "Adom Inc.",+  "license": "MIT",+  "spawn": {+    "kind": "python",+    "entrypoint": "server.py",+    "port": 0,+    "healthEndpoint": "/health",+    "stopMethod": "kill",+    "killImageName": "python.exe",+    "persistent": true+  },+  "verbPrefixes": [+    "fusion_"+  ],+  "verbs": [+    "fusion_aps_browse",+    "fusion_aps_create_folder",+    "fusion_aps_download",+    "fusion_aps_file_info",+    "fusion_aps_get",+    "fusion_aps_open",+    "fusion_aps_recent",+    "fusion_aps_search",+    "fusion_aps_set_client_id",+    "fusion_aps_signin",+    "fusion_aps_status",+    "fusion_aps_upload",+    "fusion_aps_versions",+    "fusion_attach_3d_package",+    "fusion_board_info",+    "fusion_build_library_3d",+    "fusion_capture_library_views",+    "fusion_cleanup_cloud_files",+    "fusion_close_window",+    "fusion_describe",+    "fusion_detect_layers",+    "fusion_dismiss_blocking_dialogs",+    "fusion_electron_pan",+    "fusion_electron_run",+    "fusion_electron_select",+    "fusion_electron_zoom",+    "fusion_export_3mf",+    "fusion_export_bom",+    "fusion_export_cpl",+    "fusion_export_dwg",+    "fusion_export_dxf",+    "fusion_export_gerbers",+    "fusion_export_iges",+    "fusion_export_obj",+    "fusion_export_step",+    "fusion_export_stl",+    "fusion_export_usdz",+    "fusion_generate_package",+    "fusion_get_app_state",+    "fusion_get_preferences",+    "fusion_install_fusion",+    "fusion_kill",+    "fusion_load_design_rules",+    "fusion_make_3d_package",+    "fusion_open_by_urn",+    "fusion_open_lbr",+    "fusion_readiness",+    "fusion_run_modeling_script",+    "fusion_search_cloud_files",+    "fusion_set_design_rules",+    "fusion_set_preference",+    "fusion_show_2d_board",+    "fusion_show_3d_board",+    "fusion_show_schematic",+    "fusion_start",+    "fusion_stop",+    "fusion_walk_cloud_tree"+  ],+  "dependencies": {+    "python": ">=3.10"+  },+  "category": "CAD",+  "tags": [+    "fusion360",+    "autodesk",+    "cad",+    "exports",+    "aps",+    "modeling"+  ],+  "docs": "https://wiki.adom.inc/adom/adom-desktop-fusion-bridge-macos",+  "platforms": {+    "windows": {+      "supported": true+    },+    "macos": {+      "supported": true,+      "reason": "Full macOS port: detect/launch/quit, the AdomBridge add-in API, AND the window-automation verbs (screenshot/click/send_key/window_info/dialog dismiss) via CGWindowList + screencapture + CGEvent + System Events."+    },+    "linux": {+      "supported": false,+      "reason": "Autodesk doesn't ship Fusion 360 for Linux \u2014 there's no host app for the add-in to attach to."+    }+  },+  "languages": [+    "Python"+  ],+  "hero": "https://wiki.adom.inc/api/v1/pages/adom-desktop-fusion-bridge/files/screenshots/hero.png",+  "releasedAt": "2026-06-26T06:00:00Z",+  "statusVerb": "fusion_get_app_state",+  "updateManifestUrl": "https://wiki.adom.inc/api/v1/pages/adom-desktop-fusion-bridge-macos/files/adom-bridge-fusion-manifest.json",+  "detect": {+    "hostApp": "Fusion 360",+    "paths": {+      "windows": [+        "%LOCALAPPDATA%\\Autodesk\\webdeploy\\production\\*\\FusionLauncher.exe",+        "%ProgramFiles%\\Autodesk\\webdeploy\\production\\*\\FusionLauncher.exe",+        "%ProgramFiles(x86)%\\Autodesk\\webdeploy\\production\\*\\FusionLauncher.exe"+      ],+      "macos": [+        "/Applications/Autodesk Fusion.app",+        "/Applications/Autodesk Fusion 360.app"+      ]+    },+    "hostAppOptionalVerbs": [+      "readiness",+      "describe",+      "get_app_state",+      "status",+      "addin_status",+      "aps_status",+      "aps_search",+      "aps_browse",+      "aps_recent",+      "install_fusion"+    ],+    "installVerb": "fusion_install_fusion"+  },+  "prewarm": {+    "assets": []+  },+  "timeouts": {+    "default": 60,+    "verbs": {+      "export_step": 360,+      "export_iges": 360,+      "export_sat": 360,+      "export_stl": 360,+      "export_3mf": 360,+      "export_usdz": 360,+      "export_obj": 360,+      "export_f3d": 360,+      "export_fbx": 360,+      "export_skp": 360,+      "export_dxf": 150,+      "export_dwg": 150,+      "export_gerbers": 210,+      "export_bom": 90,+      "export_cpl": 90,+      "export_board_image": 90,+      "close_all_documents": 90,+      "walk_cloud_tree": 620,+      "search_cloud_files": 200,+      "aps_open": 150,+      "run_modeling_script": 180,+      "generate_package": 120,+      "make_3d_package": 200,+      "build_library_3d": 1800,+      "capture_library_views": 600,+      "start": 90,+      "install_fusion": 90,+      "set_preference": 40,+      "get_preferences": 25,+      "demo": 300,+      "signin": 150+    },+    "prefixes": [+      {+        "prefix": "open",+        "seconds": 150+      }+    ]+  },+  "updateManifestUrls": {+    "windows": "https://wiki.adom.inc/api/v1/pages/adom-desktop-fusion-bridge/files/adom-bridge-fusion-manifest.json",+    "macos": "https://wiki.adom.inc/api/v1/pages/adom-desktop-fusion-bridge-macos/files/adom-bridge-fusion-manifest.json"+  }+}\ No newline at end of file
describe.pyadded+252
@@ -0,0 +1,252 @@+"""fusion_describe — self-describe the bridge's verb surface for Adom Desktop.++AD v1.9.23+ added a Verbs tab to each bridge's detail pop-out (lists verbs,+expands each for its I/O + timeout + status schema, with an inline runner). AD+does NOT hardcode a cloud-owned bridge's verbs, so the bridge must self-describe.+AD POSTs {command:"describe", args:{}} and caches the result at ~/.adom/bridge-verbs/.++Each entry: name, summary, input, output, timeoutSeconds, statusVerb, longRunning,+example. Keep this in step with the actual handlers as verbs are added.+"""++_STATUS = "fusion_get_app_state"++# Compact source table: name -> (summary, input, output, timeout, statusVerb, longRunning, example)+_T = [+    # ── Lifecycle ──────────────────────────────────────────────────────────+    ("fusion_start", "Launch Fusion 360 (if needed) and wait for the AdomBridge add-in to be ready.",+     {}, {"success": "bool", "addinReady": "bool", "status": "str"}, 150, None, True, {}),+    ("fusion_stop", "Gracefully STOP Fusion 360: close docs cleanly + WM_CLOSE, then wait. NO force-kill - the clean opposite of fusion_start. If a window will not close it returns failure; use fusion_kill then.",+     {"skipCleanClose": "optional bool"}, {"success": "bool", "output": "str"}, 60, None, False, {}),+    ("fusion_kill", "Force-KILL Fusion 360 (taskkill /F) - the desperate path for when fusion_stop cannot close it (stuck modal / wedged process). Closes docs cleanly first when reachable.",+     {"skipCleanClose": "optional bool"}, {"success": "bool", "output": "str"}, 30, None, False, {}),+    ("fusion_close_window", "Close the active Fusion document/window.",+     {"name": "optional str (default: active)"}, {"success": "bool"}, 30, None, False, {}),+    ("fusion_get_app_state", "Current app state: running, active document, workspace, isElectronics. The poll/status verb for long-running calls.",+     {}, {"activeDocument": "str", "activeWorkspace": "str", "isElectronics": "bool"}, 20, None, False, {}),+    ("fusion_readiness", "FAST readiness check (does NOT launch Fusion): is the Fusion host app installed + running + the bridge ready to drive? AD DETECTS Fusion (never installs it) via bridge.json 'detect', and auto-installs Python if missing (AD >=1.9.47). Call this before driving Fusion; if installed-but-not-running, fusion_start. SELF-HEALS the seat/licensing dialog (background UIA + screenshot-verify) whenever it detects one. Pairs with AD's bridge_readiness.",+     {}, {"installed": "bool", "running": "bool", "ready": "bool", "hostApp": "str", "bridgeVersion": "str"}, 15, None, False, {}),++    ("fusion_new_electronics_from_eagle", "Import a legacy EAGLE .sch (+ paired .brd) into a NEW Fusion electronics design so the parts INSTANTIATE (schematic + populated board, lands in the PCB editor). The ONLY way to author a board from EAGLE source: Document.newDesignFromLocal opens the schematic editor but does NOT instantiate parts, and the Fusion-native .fsch/.fbrd container is opaque binary you can't build offline. This fires Fusion's own ImportSCHAndBRDCmd and drives BOTH native Open dialogs (the .sch then the .brd) in the BACKGROUND via desktop_ui_click by accessible name (no foreground). Stage both files to Windows first (send_files). After: fusion_show_2d_board, RATSNEST + 'AUTO ;' to autoroute, fusion_show_3d_board for 3D.",+     {"schPath": "required str (Windows path to .sch)", "brdPath": "optional str (defaults to sibling .brd)"},+     {"success": "bool", "imported": "list"}, 200, None, False,+     {"schPath": "C:/Users/me/adom-lib/MyBoard.sch", "brdPath": "C:/Users/me/adom-lib/MyBoard.brd"}),++    ("fusion_notify_owner", "LAST-RESORT human escalation: toast the user's MAIN computer (fans out cross-AD to every peer on the relay, so it reaches them even when this bridge runs on an unattended VM). ONLY for true human walls - password/2FA entry, UAC elevation, a physical step. Exhaust programmatic options first (UIA background clicks, seat auto-resolve, warm-SSO sign-in). After sending, WAIT and poll fusion_readiness; do not re-toast within a few minutes.",+     {"title": "optional str", "body": "required str", "level": "optional str info|warning|error"},+     {"success": "bool", "targets": "list"}, 20, None, False,+     {"title": "Fusion needs you", "body": "Please complete the Autodesk 2FA prompt on winvm - everything else is done."}),++    ("fusion_signin", "Sign Fusion in through the CORRECT browser profile - the fix for Fusion's dumb OAuth that fires at the OS-DEFAULT browser and lands in the wrong Autodesk account. Fusion opens its sign-in in whatever browser is default (e.g. a personal Chrome), but a user's Autodesk seat often lives in a different profile (work). This verb reads the FULL authorize URL (client_id/PKCE/state/request_id) that Fusion wrote into that wrong browser's HISTORY and re-opens it in the RIGHT profile IN THE BACKGROUND; the URL completes back to the running Fusion via the idmgr/callback + autodesk:// handoff, so the browser no longer has to be the OS default. Pass {profile:'chrome:[email protected]'} to fix + remember your Autodesk profile; else it probes each profile for a live Autodesk session (or asks). Staged: if Fusion hasn't opened the browser yet it returns stage:'click_signin' so you click Fusion's Sign In first. BEST: pass {auto:true} to run the WHOLE chain in ONE server-side call - it clicks Fusion's Sign In, polls the browser history on-box for the fresh authorize URL, and re-opens it in the target profile, all without extra remote round-trips, so it fits inside Fusion's ~2-min OAuth request expiry even on a slow/flaky relay (the manual staged path is the fallback). Fusion's request EXPIRES in ~2 min, so a stale captured URL returns stage:'stale' - restart Fusion (fusion_stop/start) for a fresh request and retry auto PROMPTLY. See the 'fusion-multiprofile-signin' skill.",+     {"profile": "optional str (chrome:<email>/edge:<email> - the profile your Autodesk account is in; remembered)", "auto": "optional bool (do click+capture+reopen in one on-box call - recommended)", "waitSec": "optional int (server-side poll budget for the fresh URL, default 32)"},+     {"stage": "str", "done": "bool", "signinWhere": "str", "signinProfile": "str", "signinProfileReason": "str", "signinWrongBrowser": "str", "signinAuthUrl": "str", "signinOpenedVia": "str (extension|extension_free)", "signinWall": "str|null (twofactor_email_code|credentials|protocol_handoff)", "notifyDelivered": "bool", "signinWallHint": "str|null", "narrate": "str"},+     120, "fusion_signin", True, {}),+    ("fusion_mcp_status", "Is Autodesk's Fusion MCP server up, and what does it expose? Autodesk + Anthropic ship a LOCAL MCP server at http://127.0.0.1:27182/mcp exposing Fusion's own text-to-CAD surface (read geometry, execute/update features, read Electronics design data). It binds LOOPBACK on the user's machine and was built for Claude Desktop running there, so a CLOUD AI cannot reach it at all - this bridge runs on that machine and proxies it for you. Returns enabled, serverInfo and the live tool list. OFF by default: if it reports enabled:false, call fusion_mcp_enable and the bridge turns it on for the user.",+     {}, {"enabled": "bool", "serverInfo": "obj", "toolCount": "int", "tools": "[{name,description}]"},+     45, "fusion_mcp_status", False, {}),+    ("fusion_mcp_enable", "Turn Autodesk's Fusion MCP server ON by driving Fusion's Preferences dialog for the user. Autodesk exposes NO API for this toggle, so the UI is the only route: this opens Preferences (Commands.Start PreferencesCommand), expands General, selects API, ticks 'Fusion MCP Server (runs locally on this device)', then clicks Apply and OK. Needs Fusion running; briefly uses the foreground and announces why with an on-screen caption. NEVER ask the user to do this by hand first - do it for them, then tell them it is handled. Note the setting is DISCARDED if Fusion is killed or restarted before Apply is clicked.",+     {}, {"enabled": "bool", "alreadyOn": "bool", "steps": "list", "serverInfo": "obj"},+     180, "fusion_mcp_status", True, {}),+    ("fusion_mcp_tools", "Full tool list from Autodesk's Fusion MCP server INCLUDING input schemas, so you can construct a valid fusion_mcp_call. These are Autodesk's tools, not this bridge's.",+     {}, {"count": "int", "tools": "list"}, 45, "fusion_mcp_status", False, {}),+    ("fusion_mcp_call", "Call any tool on Autodesk's Fusion MCP server (fusion_mcp_read, fusion_mcp_update, fusion_mcp_execute, fusion_mcp_electronics_read). The bridge handles the MCP streamable-HTTP handshake for you (initialize -> MCP-Session-Id -> notifications/initialized) and re-establishes a dropped session automatically. MCP acts on the ACTIVE Fusion document, so open one first. PREFER a native fusion_* verb when one exists - they are tested here and return richer hints - and reach for MCP for Autodesk's text-to-CAD surface.",+     {"tool": "required str (from fusion_mcp_tools)", "arguments": "optional obj (per that tool's inputSchema)", "timeout": "optional int seconds, default 120"},+     {"result": "obj", "tool": "str"}, 150, "fusion_mcp_status", True, {"tool": "fusion_mcp_read", "arguments": {"queryType": "summary"}}),+    ("fusion_mcp_resources", "List Autodesk MCP resources, or read one by uri. These are mostly the Electronics entity schemas (resource://mcp.electronics_schema_*) that describe what fusion_mcp_electronics_read can return.",+     {"uri": "optional str (omit to list)"}, {"count": "int", "resources": "[str]", "result": "obj"},+     60, "fusion_mcp_status", False, {}),+    ("fusion_prefs_open", "Open Fusion's Preferences dialog and optionally jump to a section, then hand back a SCREENSHOT + shotId you can click in. This is how you reach ANY Fusion preference: the Python API exposes only a thin slice (theme/orbit/units, debuggingPort, developer tools) and everything else, including the MCP server toggle, is UI-only. Sections: general, api, design, manufacture, electronics, render, drawing, material, graphics, network, preview features. Child sections under General are lazily rendered by Qt and never appear in the UIA tree, which is why this returns an image to click rather than control names. ALWAYS finish with fusion_prefs_close {save:true} - nothing is saved otherwise, and killing/restarting Fusion first discards the change.",+     {"section": "optional str (see knownSections in the response)"},+     {"hwnd": "int", "shotId": "str", "screenshot": "str", "knownSections": "[str]", "steps": "list"},+     120, "fusion_get_preferences", True, {"section": "api"}),+    ("fusion_prefs_close", "Apply+OK (save:true, the default) or Cancel Fusion's Preferences dialog. Settings changed via fusion_prefs_open are NOT persisted until this is called with save:true.",+     {"save": "optional bool, default true"}, {"closed": "bool", "saved": "bool"},+     60, "fusion_get_preferences", False, {"save": True}),+    ("fusion_set_auto_update", "Turn AUTOMATIC Fusion updating on/off for this user. ON BY DEFAULT, and deliberately INVISIBLE: Fusion ships updates constantly and nags with an 'Update Now / Update Later' panel plus a '14 days until Fusion must update' countdown. Every fusion_readiness call checks for that offer and, if present, the bridge clicks it IN THE BACKGROUND (UIA, no foreground, no caption) so the download starts and the newer build comes up on the next launch. The user should never have to click it. Call with no args to read the current setting; {enabled:false} opts out and the choice is STICKY (~/.adom/fusion-bridge/prefs.json) - once a user opts out, NEVER click their update prompts again. Tell the user this is handled for them rather than asking them to update.",+     {"enabled": "optional bool (omit to read current value)"},+     {"autoUpdateFusion": "bool", "narrate": "str"},+     30, "fusion_readiness", True, {"enabled": True}),+    ("fusion_signin_2fa", "Submit Autodesk's emailed 6-DIGIT verification code to finish a Fusion sign-in, typed IN THE BACKGROUND (UIA SetValue + Invoke - never steals the user's foreground or moves their cursor). Exists so you can finish a login END TO END for the user instead of parking them on a 2FA screen: if `adom-google` is available in your container, read the code out of their Gmail (`adom-google gmail search 'from:autodesk verification code' --limit 1`), pull the 6 digits, and call this. If adom-google is NOT installed, tell the user that installing it would let you automate logins like this, then let them type it. NEVER ask the user for a code you could read yourself. The bridge ALSO toasts the user's desktop whenever it hits a human wall, so you do not need to ask it to.",+     {"code": "required str (the 6 digits; non-digits are stripped)", "hwnd": "optional int (the 2FA window; auto-detected)"},+     {"submitted": "bool", "steps": "list", "narrate": "str"},+     90, "fusion_readiness", True, {"code": "123456"}),+    ("fusion_demo", "FIRST-TIME-USER DEMO in one verb - the thing to run when someone new wants to SEE what this bridge does (HD's installer calls this). Takes them from nothing to a real board: launches Fusion, FINISHES the Autodesk sign-in - it OPENS the sign-in in the user's NATIVE browser IN THE BACKGROUND (never interrupting their work) and returns signinWhere/signinProfile/signinSession so you can tell them exactly where it is waiting, then offer three paths: they finish it, you foreground it, or (with their OK) you drive it. Native browser via ABE/nbrowser_* because that profile is already signed into Autodesk - never pup, which is anonymous, sets up APS cloud search (or explains it if declined) and runs a LIVE sample search so they see 2-second results, then opens an electronics PROJECT and walks SCHEMATIC -> 2D BOARD -> 3D BOARD, screenshotting each view to show them. STAGED + RESUMABLE: every call advances as far as it safely can and returns stage/done/narrate/screenshots plus a _hint with the exact next action; keep calling it until done:true. NEVER leave a first-time user parked on the sign-in screen - that is the failure this verb exists to prevent. See the 'fusion-demo' skill.",+     {"query": "optional str (design to demo; else picked from APS search)", "stage": "optional str ('skip_aps' to proceed without cloud search)"},+     {"stage": "str", "done": "bool", "narrate": "str", "screenshots": "[{label,path}]", "steps": "[str]", "apsSampleSearch": "[{name,project}]"},+     240, "fusion_demo", True, {}),++    # ── Cloud search & files (APS) ─────────────────────────────────────────+    ("fusion_aps_status", "APS state: configured, signed in, token live, never-charge meter.",+     {}, {"configured": "bool", "signedIn": "bool", "neverCharge": "bool"}, 20, None, False, {}),+    ("fusion_aps_set_client_id", "Set the org's APS (PKCE) client id used for cloud search.",+     {"clientId": "required str"}, {"success": "bool"}, 20, None, False, {"clientId": "D5nn...EPAq"}),+    ("fusion_aps_signin", "Open the Autodesk sign-in in the REMEMBERED browser+profile (not the OS default); a background listener captures the token. Pass {exe,profileDir,name} to use+remember a specific browser, or {allowDefaultBrowser:true} to fall back to the OS default. If nothing is remembered, returns needsExtensionOpen so the caller opens authUrl in the user's real browser via nbrowser_open_window.",+     {"exe": "optional str (browser binary to launch+remember)", "profileDir": "optional str (e.g. 'Default','Profile 2')", "name": "optional str", "allowDefaultBrowser": "optional bool"},+     {"success": "bool", "authUrl": "str", "openedVia": "str", "needsExtensionOpen": "bool"}, 30, "fusion_aps_status", False, {}),+    ("fusion_aps_set_browser", "Remember the browser+profile that authed to Autodesk so every later sign-in reuses it (power users have many browsers/profiles; the OS default is usually the wrong one). Call after a driven sign-in succeeds.",+     {"name": "optional str", "exe": "str (browser binary) OR how:'extension'", "profileDir": "optional str", "how": "optional 'extension'|'launch'"},+     {"success": "bool", "browser": "{name,exe,profileDir}"}, 10, None, False, {"name": "Edge", "exe": "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe", "profileDir": "Default"}),+    ("fusion_aps_get_browser", "Show the remembered Autodesk sign-in browser (None until set).",+     {}, {"success": "bool", "browser": "{name,exe,profileDir}|null"}, 10, None, False, {}),+    ("fusion_aps_forget_browser", "Forget the remembered Autodesk sign-in browser (re-detect next time).",+     {}, {"success": "bool", "cleared": "bool"}, 10, None, False, {}),+    ("fusion_aps_search", "Server-indexed search across the whole team hub (seconds, not a 30-min folder walk).",+     {"query": "required str", "limit": "optional int (default 50)", "hubId": "optional str", "projectId": "optional str"},+     {"count": "int", "results": "[{name,id,projectName,lastModified}]"}, 60, None, False, {"query": "Molecule", "limit": 10}),+    ("fusion_aps_open", "Find a cloud design by name and open it in Fusion (any folder depth). Fire-and-poll.",+     {"query": "required str", "wait": "optional bool"}, {"opening": "bool", "match": "{name}", "statusVerb": "str"}, 60, _STATUS, True, {"query": "BME690 Molecule"}),+    ("fusion_open_by_urn", "Open a cloud ELECTRONICS DESIGN by URN. PCB/ELECTRONICS NAV RULE: a board is NOT a standalone file - the schematic, 2D board and 3D board are VIEWS inside ONE electronics DESIGN. Open the DESIGN document first (fusion_open_cloud_file or fusion_open_by_urn), THEN switch to its schematic and its 2D board (fusion_show_2d_board) and 3D board (fusion_show_3d_board). A Select-Electronics-Design-File picker IS that design list of its schematic + board. An EMPTY 2D board usually means you opened a derivative or the wrong file, or it is out of sync - reopen the parent electronics DESIGN and switch to its board view; do NOT open a .brd or .sch as a standalone file.",+     {"urn": "required str"}, {"success": "bool", "output": "str"}, 240, _STATUS, True, {"urn": "urn:adsk.wipprod:fs.file:vf.xxxx?version=1"}),+    ("fusion_aps_browse", "Browse hubs/projects/folders without launching Fusion.",+     {"hubId": "optional str", "projectId": "optional str", "folderId": "optional str"}, {"items": "[{name,type,id}]"}, 60, None, False, {}),+    ("fusion_aps_recent", "Most-recently-modified designs across the team hub, newest first.",+     {"limit": "optional int (default 25)"}, {"count": "int", "results": "[...]"}, 60, None, False, {"limit": 25}),+    ("fusion_aps_file_info", "Version history + who/when/size for a file (tip + recent versions).",+     {"query": "str  OR  projectId+urn"}, {"versionCount": "int", "tip": "{...}", "versions": "[...]"}, 40, None, False, {"query": "BME690 Molecule"}),+    ("fusion_aps_versions", "Full (uncapped) version history of a file.",+     {"query": "str  OR  projectId+urn"}, {"versionCount": "int", "versions": "[...]"}, 40, None, False, {"query": "BME690 Molecule"}),+    ("fusion_aps_download", "Download a cloud file to the local machine (no Fusion needed).",+     {"query": "str OR projectId+urn", "saveDir": "optional str", "fileName": "optional str"}, {"path": "str", "bytes": "int"}, 90, None, False, {"query": "BME690 Molecule"}),+    ("fusion_aps_upload", "Upload a local file as a NEW cloud file (free Data Management; needs data:write scope). ⛔ FOLDER HYGIENE: NEVER pass a project ROOT folderId - the bridge REFUSES it (refused_root_upload). Loose files in a shared root clutter the team's cloud. Create/choose a real subfolder first (fusion_aps_create_folder under an 'Adom AI Workspace' folder), or just use fusion_make_3d_package / fusion_build_library_3d which auto-target a non-root workspace. To RELOCATE an existing file, MOVE it (preserves its urn) - do NOT delete + re-upload (mints a new urn, breaks 3D bindings). See the fusion-cloud-hygiene skill.",+     {"projectId": "required str", "folderId": "required str (NON-ROOT subfolder)", "localPath": "required str", "fileName": "optional str"},+     {"itemUrn": "str", "bytes": "int"}, 90, None, False, {"projectId": "a.YnVz...", "folderId": "urn:...", "localPath": "C:/x.f3d"}),+    ("fusion_aps_create_folder", "Create a subfolder in a project (free; needs data:create scope). Use this to make an 'Adom AI Workspace' folder + per-task subfolders so the bridge never dumps loose files in the shared project root. See fusion-cloud-hygiene.",+     {"projectId": "required str", "parentFolderId": "required str", "name": "required str"}, {"folderId": "str"}, 50, None, False, {"projectId": "a.YnVz...", "parentFolderId": "urn:...", "name": "Adom AI Workspace"}),+    ("fusion_aps_get", "Raw authenticated GET against a free APS path (dev/verify helper).",+     {"path": "required str"}, {"status": "int", "body": "obj"}, 40, None, False, {"path": "/project/v1/hubs"}),+    ("fusion_walk_cloud_tree", "⛔ DISABLED (returns an error): the in-app add-in walk took 30+ min and CRASHED Fusion (WinError 10054). It is hard-blocked in the bridge. Use fusion_aps_search / fusion_aps_open. See the 'fusion-aps-search' skill.",+     {}, {"disabled": "bool"}, 15, None, False, {}),+    ("fusion_search_cloud_files", "⛔ DISABLED (returns an error): the in-app add-in search took 30+ min and CRASHED Fusion (WinError 10054). It is hard-blocked in the bridge. Use fusion_aps_search {query} — server-indexed, seconds, no Fusion. See the 'fusion-aps-search' skill.",+     {"query": "required str"}, {"disabled": "bool"}, 15, None, False, {"query": "Molecule"}),++    # ── Electronics ────────────────────────────────────────────────────────+    ("fusion_show_schematic", "Switch the OPEN electronics design to its SCHEMATIC view (the symmetric partner of fusion_show_2d_board / fusion_show_3d_board, via Fusion's SwitchSchDocCmd). A VIEW of the project, not a standalone file. Drive it for demos with fusion_electron_zoom / _pan / _select.",+     {}, {"success": "bool", "activeWorkspace": "str", "productType": "str"}, 70, None, True, {}),+    ("fusion_show_2d_board", "Switch the OPEN electronics design to its 2D PCB Editor (board layout) view. This is a VIEW of the project, not a file to open standalone - if the board is empty, you opened a child/derivative instead of the EcadDesignProductType PROJECT; reopen the project. Drive the view with fusion_electron_run WINDOW commands.",+     {}, {"activeWorkspace": "str"}, 70, None, True, {}),+    ("fusion_show_3d_board", "Switch the OPEN electronics design to its 3D PCB view (populated board). A VIEW of the project, not a standalone file. Orbit it for demos via fusion_run_modeling_script (app.activeViewport.camera + vp.refresh()).",+     {}, {"activeWorkspace": "str", "screenshots": "[...]"}, 70, None, True, {}),+    ("fusion_open_by_urn_note", "(see fusion_open_by_urn)", {}, {}, 30, None, False, {}),+    ("fusion_board_info", "Raw board geometry XML (copper/arcs/lines) for the open board.",+     {}, {"rawXml": "str"}, 60, None, False, {}),+    ("fusion_open_lbr", "Import an EAGLE .lbr library into Fusion's Electronics LIBRARY editor (Content Manager / Electronics Library workspace), not a PCB design. PITFALL: filePath MUST be a WINDOWS-local path (C:/...). The chip-fetcher/adom-lbr pipeline runs in the cloud container, and there is NO container-to-Windows push verb, so STAGE the .lbr onto Windows first (serve it on a proxied port + Invoke-WebRequest via shell_execute), then pass the C:/ path. PITFALL: an adom-lbr .lbr is 2D ONLY - symbol + footprint + a PLACEHOLDER 3D package; the real 3D chip is NOT attached (that needs a Fusion cloud URN). To attach the 3D, see the 'fusion-libraries' skill. Pass verify:true to round-trip-confirm Fusion parsed the deviceset, then check fusion_get_app_state (activeWorkspace 'Electronics Library').",+     {"filePath": "required str (.lbr WINDOWS path C:/...; stage from container first)", "symbolName": "optional str", "verify": "optional bool"},+     {"success": "bool", "postOpenScreenshot": "{savedTo}"}, 50, None, False, {"filePath": "C:/Users/<user>/adom-lib/nRF54L15.lbr"}),+    ("fusion_attach_3d_package", "Attach a real 3D chip model to a library package, end to end: opens the .lbr (library active), runs Electron.Create3DPackage to enter the Package3DEnvironment showing the footprint, imports the STEP + auto-orients it flat on the footprint, then executes Package3DStop (FINISH). This BINDS the 3D onto the deviceset (Content Manager shows the 3D nested under the package; the Packages 'Package' column flips Placeholder->part-name). ONE desktop-side step remains: Fusion pops a modal Save dialog (an OWNED popup) - the response _hint gives the exact desktop_ui_click to confirm it. AFTER: re-grab desktop_screenshot_window and check ownedPopupCount for errors; the 3D preview LAGS a beat before showing the real chip. Both paths (filePath/modelPath) are WINDOWS paths - stage from the container first.",+     {"filePath": "required str (.lbr WINDOWS path C:/...)", "modelPath": "required str (.step WINDOWS path C:/...)", "packageName": "optional str"},+     {"success": "bool", "savePending": "bool", "data": "{steps}", "_hint": "the Save-dialog click + verify steps"}, 240, _STATUS, True, {"filePath": "C:/Users/<user>/adom-lib/ADS8588SIPM.fusion.lbr", "modelPath": "C:/Users/<user>/adom-lib/ADS8588SIPM.step", "packageName": "ADS8588SIPM"}),+    ("fusion_install_fusion", "Install Fusion 360 FOR the user - downloads Autodesk's official Client Downloader and streams the free trial silently, with NO shell_execute and NO AD approval gate (runs inside the trusted bridge). Elevation-aware: --globalinstall when admin, PER-USER otherwise (a non-elevated globalinstall dies silently on UAC - learned live). Returns promptly; poll fusion_readiness (reports installing:true) until installed:true, then fusion_start. Declared as detect.installVerb so AD's bridge_readiness recommends it.",+     {}, {"success": "bool", "installing": "bool", "alreadyInstalled": "bool?", "mode": "globalinstall|per-user", "statusVerb": "str"}, 90, _STATUS, True, {}),+    ("fusion_generate_package", "Generate an IPC-7351-compliant parametric 3D package via Fusion's BUILT-IN ElectronicsPackageGenerator (EPG) - ~50 package families (chip/soic/qfn/qfp/bga/sot23/dfn/melf/ecap/crystal/headers/...), each a few seconds, ZERO GUI. Optionally LASER-ETCH a marking (MPN / '103') into the body top as REAL cut geometry (survives STEP), and export STEP in the same call - the royalty-free, license-clean path to a whole component library (our own generated output, not vendor models). Proven live: 0603 + '103' etch + STEP in ~2s.",+     {"type": "required str (EPG family, e.g. chip|soic|qfn|qfp|bga|sot23|dfn2|melf|ecap|crystal|header_straight - see supportedTypes in the error for the full list)", "params": "optional dict (generator dims in MM by default, e.g. chip: {D,E,A,L,L1}; soic: {A,A1,b,D,E,E1,e,L,DPins}; omitted keys use EPG defaults)", "unitsCm": "optional bool (params already EPG-native cm)", "etch": "optional str (marking text on the chip top: MPN / '103'; multi-line with newline, e.g. MPN+variant - laid along the LONGEST face axis)", "etchStyle": "optional str raised|engraved (default raised = thin WHITE positive extrude, silkscreen-style contrast; engraved = sunken cut)", "etchDepthMm": "optional float (marking height/depth, default 0.03)", "etchHeightMm": "optional float (text height; default auto-fit: top-5%-band face, 10% margin, width-aware)", "outputStep": "optional str (WINDOWS path; exports STEP incl. the marking)"},+     {"success": "bool", "bodies": "[{name,vol}]", "etched": "str|null", "stepPath": "str|null", "manifest": "obj (settings+why+bboxes; also written as <step>.manifest.json sidecar for marking refreshes)", "manifestPath": "str|null", "epgDir": "str"}, 120, _STATUS, True, {"type": "chip", "params": {"D": 1.6, "E": 0.8, "A": 0.45, "L": 0.3, "L1": 0.3}, "etch": "103", "outputStep": "C:/tmp/ADOM-R0603-103.step"}),+    ("fusion_make_3d_package", "Create a RENDERING component 3D package (FOOTPRINT + chip, aligned) for ONE part, fully programmatically with ZERO GUI dialogs. Opens the .lbr, runs Electron.Create3DPackage to load the package's footprint into a generator doc, imports the STEP onto it, orients it flat, saveAs an .f3d (skips the FINISH Save dialog + the two unbeatable 'Fusion360' CEF modals), uploads the f3d via APS, and returns an fs.file:vf wip_urn to hand-write into the library's <packages3d>. projectId/folderId default to the MAIN-project upload folder. Pass captureLabel to also get a BEFORE (footprint) + AFTER (chip placed) screenshot. PITFALL: a RAW STEP upload binds but renders NOTHING ('Thumbnail download failed') - this verb makes an f3d, which renders. Prefer fusion_build_library_3d for many parts.",+     {"lbrPath": "required str (.lbr WINDOWS path; its FIRST package's footprint is loaded)", "modelPath": "required str (.step WINDOWS path)", "projectId": "optional str (default MAIN-project)", "folderId": "optional str (default upload folder)", "fileName": "optional str", "captureLabel": "optional str (capture before/after)", "orient": "optional bool (default true)"},+     {"success": "bool", "wip_urn": "str", "dims_mm": "[x,y,z]", "f3d": "str", "before": "str|null", "after": "str|null"}, 200, _STATUS, True, {"lbrPath": "C:/tmp/newlib/R_4k7.lbr", "modelPath": "C:/tmp/newlib/R_4k7.step", "captureLabel": "R_4k7"}),+    ("fusion_build_library_3d", "Build a RENDERING multi-part 3D library in ONE call - the whole programmatic pipeline. For each part it makes the footprint+chip f3d package (no GUI dialogs, optional before/after screenshots) and collects the wip_urn, then injects ALL bindings into the combined .lbr in one pass (no hand XML surgery) and opens the finished library once. This is the verb for a basic-parts sampler / any many-part library; it replaces the per-part make_3d_package loop + manual binding. projectId/folderId default to the MAIN-project upload folder. Each part is independent, so re-run just the failed parts if Fusion resets mid-run.",+     {"lbrPath": "required str (combined .lbr WINDOWS path to bind + open)", "parts": "required [{package, lbrPath (per-part footprint .lbr), modelPath (.step)}]", "outLbrPath": "optional str (default: overwrite lbrPath)", "capture": "optional bool (default true)", "projectId": "optional str", "folderId": "optional str", "openWhenDone": "optional bool (default true)"},+     {"success": "bool", "boundLbr": "str", "partsBound": "int", "partsTotal": "int", "parts": "[{package,success,wip_urn,dims_mm,error}]", "screenshots": "[{package,stage,path}]", "opened": "bool"}, 1800, _STATUS, True, {"lbrPath": "C:/tmp/newlib/AdomBasicParts2.lbr", "parts": [{"package": "R_4k7", "lbrPath": "C:/tmp/newlib/R_4k7.lbr", "modelPath": "C:/tmp/newlib/R_4k7.step"}]}),+    ("fusion_capture_library_views", "Capture the LIBRARY-EDITOR views EEs trust: the schematic SYMBOL (full pinout), the FOOTPRINT (pads + layer stack), and the COMPONENT/device view (Content Manager: symbol + the package table with the footprint<->package Mapped check + pin/pad counts). The 3D before/after shots don't show these. Requires the .lbr OPEN in the Electronics Library workspace (fusion_open_lbr first). Runs EDIT <pkg>.sym/.pac/.dev + WINDOW FIT + a background hwnd screenshot per view; returns the PNG paths on the box (C:/tmp/conduit-screenshots - pull with desktop_pull_file). EDIT uses the DEVICESET name (e.g. ESP32-S3FN8).",+     {"packages": "required [<deviceset name>] (or 'package': single name)", "views": "optional subset of ['component','symbol','footprint'] (default all)", "settle": "optional float secs after each EDIT before capture (default 1.5; raise if a shot shows the PREVIOUS part)"},+     {"success": "bool", "captured": "[{package,view,path,ok}]"}, 300, _STATUS, True, {"packages": ["ESP32-S3FN8", "ATSAMD51J20A-AUT"]}),+    ("fusion_cleanup_cloud_files", "PRECISELY delete a list of cloud files by lineage urn - SAFE cleanup of AI-created clutter. Deletes ONLY the exact fileIds given (never name-guessing), so it can't touch a teammate's file in a shared folder. Loops server-side. Get the ids from fusion_aps_browse (item .id). Use this to remove f3d files the bridge created. A big list takes minutes (relay may time out at ~60s while deletes continue server-side - re-browse to confirm).",+     {"fileIds": "required [<lineage urn>]", "projectName": "optional str (default active project)", "folderPath": "optional str (default root - where the files live)"},+     {"success": "bool", "deletedCount": "int", "failedCount": "int", "failed": "[{fileId,error}]"}, 1800, _STATUS, True, {"fileIds": ["urn:adsk.wipprod:dm.lineage:abc123"], "projectName": "Adom"}),+    ("fusion_run_modeling_script", "Run an adsk.fusion modeling script in the live session (sketches/extrudes/params). Free programmatic CAD.",+     {"script": "required str (Python using adsk; globals: adsk, app, ui, design)"},+     {"result": "obj", "documentName": "str"}, 180, None, True, {"script": "import adsk.fusion\n# ...build geometry..."}),++    ("fusion_assembly_bom", "Structured, kit-aware MECHANICAL bill of materials for the active Design assembly (the counterpart to the electronics-only fusion_export_bom). Recurses organizational subassemblies but counts a physical part or a purchased kit/unit ONCE, so hardware modeled inside a kit (a '... with fasteners' bracket, a bearing/pulley) is NOT double-counted the way a flat allOccurrences walk counts it. Matches Fusion's Manage -> BOM quantities. Optionally writes a CSV.",+     {"treatAsUnit": "optional [str] name substrings counted as one unit (default ['with fasteners'])", "exclude": "optional [str] top-level name prefixes to skip", "includePhysicalProperties": "optional bool (adds volume_cm3/mass_kg per line)", "outputPath": "optional str (Windows CSV path)"},+     {"success": "bool", "design": "str", "partCount": "int", "totalInstances": "int", "parts": "[{componentName, partNumber, description, material, quantity, bodies}]"},+     120, None, False, {"treatAsUnit": ["with fasteners"], "includePhysicalProperties": True}),++    ("fusion_physical_properties", "Per-component physical properties (volume cm3, mass kg, density, area, center of mass) for the active design. Reads them directly so BOM/costing tools no longer have to run getPhysicalProperties inside a modeling script. Pass names to scope to specific components.",+     {"names": "optional [str] component names to measure (default all)", "accuracy": "optional low|medium|high|veryhigh (default low)"},+     {"success": "bool", "count": "int", "properties": "{name: {volume_cm3, mass_kg, density, area_cm2, center_of_mass}}"},+     120, None, False, {"accuracy": "low"}),++    ("fusion_set_preference", "Set Fusion appearance/navigation preferences in the LIVE session - applies immediately, NO restart. Keys: theme (light/darkblue/darkgray/classic/device/dark; some builds only ship LightGray/DarkBlue/Device, failures reported per-key), invertScrollZoom (bool - mouse scroll/zoom direction), orbitScheme (fusion360/alias/inventor/solidworks/tinkercad/powermill), modelingOrientation (yup/zup), gestureNav (bool), cameraPivot (bool), lengthUnit (mm/cm/m/in/ft - active design). Per-key outcome in `applied`, resulting state in `current`.",+     {"theme": "optional str", "invertScrollZoom": "optional bool", "orbitScheme": "optional str", "modelingOrientation": "optional str", "gestureNav": "optional bool", "cameraPivot": "optional bool", "lengthUnit": "optional str"},+     {"applied": "obj", "current": "obj"}, 30, None, True, {"theme": "dark"}),++    ("fusion_get_preferences", "Read current Fusion appearance/navigation preferences (theme, activeTheme, invertScrollZoom, orbitScheme, modelingOrientation, gestureNav, cameraPivot, lengthUnit) as friendly values - the same keys fusion_set_preference accepts.",+     {}, {"current": "obj"}, 20, None, False, {}),++    # ── CAD & 3D export ────────────────────────────────────────────────────+    ("fusion_export_step", "Export the active design to STEP (needs the 3D view).",+     {"outputPath": "required str"}, {"format": "str", "fileSizeKB": "int"}, 300, None, True, {"outputPath": "C:/out/board.step"}),+    ("fusion_export_iges", "Export to IGES.", {"outputPath": "required str"}, {"format": "str"}, 300, None, True, {"outputPath": "C:/out/board.iges"}),+    ("fusion_export_stl", "Export to STL mesh.", {"outputPath": "required str"}, {"format": "str"}, 300, None, True, {"outputPath": "C:/out/part.stl"}),+    ("fusion_export_3mf", "Export to 3MF mesh.", {"outputPath": "required str"}, {"format": "str"}, 300, None, True, {"outputPath": "C:/out/part.3mf"}),+    ("fusion_export_usdz", "Export to USDZ (AR / Hydrogen 3D).", {"outputPath": "required str"}, {"format": "str"}, 300, None, True, {"outputPath": "C:/out/part.usdz"}),+    ("fusion_export_optimized_glb", "Fusion board -> wiki-grade optimized GLB. Exports STEP (+ optional silkscreen) and submits it to service-step2glb molecule mode (anchor to MP pins + silk bake + gold pins + join/weld/prune + Draco): ~465KB/~31 draw calls vs a raw ~16MB/~25000 that halts the viewer. Bounded-waits `wait`s (default 90); small boards return complete, big boards return {pending, jobId} - finish with fusion_fetch_optimized_glb. Use for a component page's component.parts.model_3d. STACKUP RULE (John 2026-07-15, see pcb-stackup skill): board bbox = the FR4 body, NEVER the whole assembly (components overhang edges + tower above); each overlay goes at ITS layer's z (copper at FR4-top, silk above mask); copper traces are REAL 35um 3D bodies colored like the FR4 - recolor them + translucent mask in the RAW GLB before optimizing to make routing visible; put the measured stackup table on the board's wiki page. PUBLISH EVERYTHING: a board's wiki page repo must carry EVERY exportable design file (.f3d/.step/.usdz/EAGLE .brd+.sch/Fusion .fbrd+.fsch/gerbers/BOM/CPL/GLBs/renders), not just the 3D - the page exists to share the design.", {"outputPath": "required str (.glb)", "silkscreen": "bool default true", "pin": "str medium|large default medium", "wait": "int seconds default 15 (keep under the ~60s relay timeout; re-call fetch until complete)"}, {"glbPath": "str", "jobId": "str", "pending": "bool", "meshesAfter": "int", "sizeBytes": "int", "moleculeAnchored": "bool", "silkscreenApplied": "bool"}, 200, None, True, {"outputPath": "C:/out/board.glb"}),+    ("fusion_fetch_optimized_glb", "Finish a fusion_export_optimized_glb job: bounded-poll the optimizer by jobId and write the GLB to outputPath when complete. Re-call until status=complete (big boards tessellate a few minutes). No Fusion needed.", {"jobId": "required str", "outputPath": "str (.glb)", "wait": "int seconds default 15 (keep under the ~60s relay timeout; re-call fetch until complete)"}, {"glbPath": "str", "status": "str", "pending": "bool", "sizeBytes": "int"}, 150, None, False, {"jobId": "abc123", "outputPath": "C:/out/board.glb"}),+    ("fusion_board_stackup", "Read a board's PHYSICAL fabrication stackup (see the pcb-stackup skill): copper layer count + copper/dielectric thicknesses from the EAGLE design rules (layerSetup/mtCopper/mtIsolate) plus the measured FR4 extent. A PCB is Cu/prepreg/Cu/core/.../Cu - the FR4 is NOT one slab. Use to build the stackup table + real-thickness exploded 3D view, and put a stackup table on every exported board's wiki page.", {}, {"layerSetup": "str", "copperLayers": "list", "copperCount": "int", "copperThickness_mm": "list", "dielectricBonds": "list (prepreg/core order)", "fr4": "{x_mm,y_mm,dielectric_mm}"}, 200, None, True, {}),+    ("fusion_export_obj", "Export to OBJ mesh.", {"outputPath": "required str"}, {"format": "str"}, 300, None, True, {"outputPath": "C:/out/part.obj"}),+    ("fusion_export_dxf", "Export 2D DXF.", {"outputPath": "required str"}, {"format": "str"}, 120, None, True, {"outputPath": "C:/out/sketch.dxf"}),+    ("fusion_export_dwg", "Export 2D DWG.", {"outputPath": "required str"}, {"format": "str"}, 120, None, True, {"outputPath": "C:/out/sketch.dwg"}),++    # ── Manufacturing ──────────────────────────────────────────────────────+    ("fusion_export_gerbers", "Run the bundled JLCPCB CAM job (auto 2/4-layer) to produce the gerber + drill ZIP.",+     {"outputDir": "optional str (default C:/tmp/adom-gerbers)"}, {"fileCount": "int", "files": "[{name,size}]", "zipPath": "str"}, 180, None, True, {"outputDir": "C:/tmp/jlc"}),+    ("fusion_export_bom", "Export a Bill of Materials CSV (grouped by value+package) from the open board.",+     {"outputPath": "optional str", "grouped": "optional bool (default true)"}, {"componentCount": "int", "grouped": "bool"}, 60, None, False, {"outputPath": "C:/tmp/bom.csv"}),+    ("fusion_export_cpl", "Export the Component Placement List (pick-and-place) CSV.",+     {"outputPath": "optional str", "side": "optional str (all|top|bottom)"}, {"topCount": "int", "bottomCount": "int"}, 60, None, False, {"outputPath": "C:/tmp/cpl.csv"}),+    ("fusion_set_design_rules", "Load manufacturing-grade DRC into the open board (JLCPCB 2/4-layer profiles).",+     {"action": "optional str (apply|export|show)", "layers": "optional str (auto|2|4)"}, {"activeWorkspace": "str", "description": "str"}, 90, None, False, {"action": "apply", "layers": "2"}),+    ("fusion_load_design_rules", "Load a bundled .edru design-rule set into the board.",+     {"layers": "optional str (auto|2|4)"}, {"success": "bool"}, 90, None, False, {}),+    ("fusion_detect_layers", "Detect 2-layer vs 4-layer board (ULP + CAM comparison).",+     {}, {"layerCount": "int", "copperLayers": "[int]"}, 90, None, False, {}),+    ("fusion_dismiss_blocking_dialogs", "Detect + classify (and optionally dismiss) blocking Fusion dialogs.",+     {}, {"dialogs": "[...]"}, 30, None, False, {}),+    ("fusion_electron_run", "Run an EAGLE/Electron command in the open board (the generic extension point, e.g. RUN <ulp>).",+     {"command": "required str"}, {"success": "bool", "output": "str"}, 90, None, False, {"command": "set confirm yes;RUN 'C:/tmp/jlcpcb_smta_exporter.ulp' 'C:/tmp/jlc'"}),+    ("fusion_electron_zoom", "Smoothly ZOOM the schematic/2D board for a recording (the whole motion is one call). factor>1 zooms in, <1 out; or fit:true. The loop runs in the add-in with a repaint per frame.",+     {"factor": "float (default 2.0)", "fit": "optional bool", "steps": "optional int (default 16)", "frameDelayMs": "optional int (default 35)"},+     {"success": "bool", "output": "str"}, 60, None, True, {"factor": 3, "steps": 20}),+    ("fusion_electron_pan", "Smoothly PAN + zoom the view to frame a board-coordinate box (mm; get part positions from fusion_board_info). Animates from where the view last was.",+     {"x1": "float", "y1": "float", "x2": "float", "y2": "float", "steps": "optional int (default 16)", "frameDelayMs": "optional int (default 35)"},+     {"success": "bool", "output": "str", "box": "[...]"}, 60, None, True, {"x1": 0, "y1": 0, "x2": 10, "y2": 8}),+    ("fusion_electron_select", "SELECT a part (by reference designator, or x/y board mm) and surface its properties - the way clicking a part reveals the properties panel. Great for showing life in a recording.",+     {"name": "str (refdes, e.g. R1)", "x": "optional float", "y": "optional float", "properties": "optional bool (default true)"},+     {"success": "bool", "output": "str", "deviceInfo": "str"}, 30, None, True, {"name": "U1"}),++    # ── Self-describe ──────────────────────────────────────────────────────+    ("fusion_describe", "Self-describe every verb the bridge exposes (this list) for AD's Verbs tab + runner.",+     {}, {"success": "bool", "verbs": "[{name,summary,input,output,timeoutSeconds,statusVerb,longRunning,example}]"}, 20, None, False, {}),+]+++def _verbs():+    out = []+    for name, summary, inp, outp, timeout, status, longr, ex in _T:+        if name.endswith("_note"):+            continue+        out.append({+            "name": name,+            "summary": summary,+            "input": inp,+            "output": outp,+            "timeoutSeconds": timeout,+            "statusVerb": status,+            "longRunning": longr,+            "example": ex,+        })+    return out+++def handle_describe(args: dict) -> dict:+    verbs = _verbs()+    # `verbs` at the TOP LEVEL is what AD's Verbs tab reads from the raw /command+    # response. AD's relay strips non-standard top-level fields on the CLI proxy+    # path, so we ALSO nest under `data` (which the relay forwards) for CLI/debug.+    return {+        "success": True,+        "bridge": "fusion360",+        "verbCount": len(verbs),+        "verbs": verbs,+        "data": {"bridge": "fusion360", "verbCount": len(verbs), "verbs": verbs},+    }
eagle_lbr.pyadded+270
@@ -0,0 +1,270 @@+"""Generate EAGLE .lbr (XML) library files for Fusion 360 Electronics.++Creates minimal but valid .lbr files that Fusion 360 can open via+Document.Open. The XML format matches EAGLE 9.7.0 as used by Fusion's+integrated Electronics workspace.++Usage:+    from eagle_lbr import build_lbr_xml, write_lbr++    # Build XML for a simple 2-pin resistor symbol+    xml = build_lbr_xml(+        library_name="MyLib",+        symbols=[{+            "name": "R",+            "description": "Resistor",+            "pins": [+                {"name": "1", "x": -5.08, "y": 0, "direction": "pas"},+                {"name": "2", "x": 5.08, "y": 0, "direction": "pas", "rot": "R180"},+            ],+            "wires": [+                {"x1": -2.54, "y1": -0.889, "x2": 2.54, "y2": -0.889, "width": 0.254, "layer": 94},+                {"x1": 2.54, "y1": 0.889, "x2": -2.54, "y2": 0.889, "width": 0.254, "layer": 94},+                {"x1": 2.54, "y1": -0.889, "x2": 2.54, "y2": 0.889, "width": 0.254, "layer": 94},+                {"x1": -2.54, "y1": -0.889, "x2": -2.54, "y2": 0.889, "width": 0.254, "layer": 94},+            ],+            "texts": [+                {"value": ">NAME", "x": 0, "y": 2.54, "size": 1.778, "layer": 95, "align": "center"},+                {"value": ">VALUE", "x": 0, "y": -2.54, "size": 1.778, "layer": 96, "align": "center"},+            ],+        }],+    )+    write_lbr(xml, "C:/tmp/MyLib.lbr")+"""++import xml.etree.ElementTree as ET+from xml.dom import minidom+++# Standard EAGLE layer definitions used by Fusion 360 Electronics.+# These are the layers from a real Fusion-generated library.+STANDARD_LAYERS = [+    (1, "Top"), (2, "Route2"), (3, "Route3"), (4, "Route4"),+    (5, "Route5"), (6, "Route6"), (7, "Route7"), (8, "Route8"),+    (9, "Route9"), (10, "Route10"), (11, "Route11"), (12, "Route12"),+    (13, "Route13"), (14, "Route14"), (15, "Route15"), (16, "Bottom"),+    (17, "Pads"), (18, "Vias"), (19, "Unrouted"), (20, "BoardOutline"),+    (21, "SilkscreenTop"), (22, "SilkscreenBottom"),+    (23, "OriginsTop"), (24, "OriginsBottom"),+    (25, "NamesTop"), (26, "NamesBottom"),+    (27, "ValuesTop"), (28, "ValuesBottom"),+    (29, "SolderMaskTop"), (30, "SolderMaskBottom"),+    (31, "StencilTop"), (32, "StencilBottom"),+    (33, "FinishTop"), (34, "FinishBottom"),+    (35, "GlueTop"), (36, "GlueBottom"),+    (37, "TestTop"), (38, "TestBottom"),+    (39, "ComponentExcludeTop"), (40, "ComponentExcludeBottom"),+    (41, "RestrictTop"), (42, "RestrictBottom"), (43, "RestrictVias"),+    (44, "Drills"), (45, "Holes"), (46, "Milling"),+    (47, "Measures"), (48, "Document"), (49, "Reference"),+    (51, "DocumentTop"), (52, "DocumentBottom"),+    (88, "SimResults"), (89, "SimProbes"),+    (90, "Modules"), (91, "Nets"), (92, "Busses"), (93, "Pins"),+    (94, "Symbols"), (95, "Names"), (96, "Values"),+    (97, "Info"), (98, "Guide"),+]+++def _add_layers(parent: ET.Element):+    """Add standard EAGLE layer definitions."""+    layers_el = ET.SubElement(parent, "layers")+    for num, name in STANDARD_LAYERS:+        attrs = {+            "number": str(num),+            "name": name,+            "blackcolor": "0xccc8c8c8",+            "whitecolor": "0xbb808080",+            "coloredcolor": "0xbb808080",+            "blackhighlight": "0xccc8c8c8",+            "whitehighlight": "0xbb808080",+            "coloredhighlight": "0xbb808080",+            "fill": "1",+            "visible": "yes",+            "active": "yes",+        }+        # Use Fusion's actual colors for key schematic layers+        if num == 94:  # Symbols+            attrs.update({+                "blackcolor": "0xccc90d0c", "whitecolor": "0xccc90d0c",+                "coloredcolor": "0xccc90d0c",+                "blackhighlight": "0xccc90000", "whitehighlight": "0xccc90000",+                "coloredhighlight": "0xccc90000",+            })+        elif num == 93:  # Pins+            attrs.update({+                "blackcolor": "0xcc3ddc97", "whitecolor": "0xcc0dab76",+                "coloredcolor": "0xcc0dab76",+                "blackhighlight": "0xcc00dc79", "whitehighlight": "0xcc00ab6f",+                "coloredhighlight": "0xcc00ab6f",+            })+        ET.SubElement(layers_el, "layer", **attrs)+++def _build_symbol_element(sym: dict) -> ET.Element:+    """Build a <symbol> element from a symbol dict.++    Symbol dict keys:+        name: str - symbol name (required)+        description: str - optional description+        pins: list of pin dicts+        wires: list of wire dicts+        texts: list of text dicts+        circles: list of circle dicts+        rectangles: list of rect dicts+    """+    el = ET.Element("symbol", name=sym["name"])++    if sym.get("description"):+        desc = ET.SubElement(el, "description")+        desc.text = sym["description"]++    for wire in sym.get("wires", []):+        attrs = {+            "x1": str(wire["x1"]), "y1": str(wire["y1"]),+            "x2": str(wire["x2"]), "y2": str(wire["y2"]),+            "width": str(wire.get("width", 0.254)),+            "layer": str(wire.get("layer", 94)),+        }+        ET.SubElement(el, "wire", **attrs)++    for circle in sym.get("circles", []):+        attrs = {+            "x": str(circle["x"]), "y": str(circle["y"]),+            "radius": str(circle["radius"]),+            "width": str(circle.get("width", 0.254)),+            "layer": str(circle.get("layer", 94)),+        }+        ET.SubElement(el, "circle", **attrs)++    for rect in sym.get("rectangles", []):+        attrs = {+            "x1": str(rect["x1"]), "y1": str(rect["y1"]),+            "x2": str(rect["x2"]), "y2": str(rect["y2"]),+            "layer": str(rect.get("layer", 94)),+        }+        ET.SubElement(el, "rectangle", **attrs)++    for pin in sym.get("pins", []):+        attrs = {"name": pin["name"]}+        attrs["x"] = str(pin.get("x", 0))+        attrs["y"] = str(pin.get("y", 0))+        if pin.get("visible"):+            attrs["visible"] = pin["visible"]+        else:+            attrs["visible"] = "off"+        attrs["length"] = pin.get("length", "short")+        if pin.get("direction"):+            attrs["direction"] = pin["direction"]+        if pin.get("swaplevel"):+            attrs["swaplevel"] = str(pin["swaplevel"])+        if pin.get("rot"):+            attrs["rot"] = pin["rot"]+        ET.SubElement(el, "pin", **attrs)++    for text in sym.get("texts", []):+        attrs = {+            "x": str(text.get("x", 0)),+            "y": str(text.get("y", 0)),+            "size": str(text.get("size", 1.778)),+            "layer": str(text.get("layer", 95)),+        }+        if text.get("align"):+            attrs["align"] = text["align"]+        t = ET.SubElement(el, "text", **attrs)+        t.text = text.get("value", "")++    return el+++def build_lbr_xml(+    library_name: str = "AdomLib",+    description: str = "",+    symbols: list[dict] | None = None,+) -> str:+    """Build a complete EAGLE .lbr XML string.++    Args:+        library_name: Library name (appears in EAGLE's library manager).+        description: Optional library description.+        symbols: List of symbol dicts. Each symbol dict has:+            - name: str (required)+            - description: str+            - pins: list of {name, x, y, direction?, rot?, visible?, length?}+            - wires: list of {x1, y1, x2, y2, width?, layer?}+            - texts: list of {value, x, y, size?, layer?, align?}+            - circles: list of {x, y, radius, width?, layer?}+            - rectangles: list of {x1, y1, x2, y2, layer?}++    Returns:+        Complete XML string ready to write to a .lbr file.+    """+    symbols = symbols or []++    root = ET.Element("eagle", version="9.7.0")+    drawing = ET.SubElement(root, "drawing")++    # Settings+    settings = ET.SubElement(drawing, "settings")+    ET.SubElement(settings, "setting", alwaysvectorfont="no")+    ET.SubElement(settings, "setting", verticaltext="up")++    # Grid+    ET.SubElement(drawing, "grid",+                  distance="0.1", unitdist="inch", unit="inch",+                  style="lines", multiple="1", display="no",+                  altdistance="0.01", altunitdist="inch", altunit="inch")++    # Layers+    _add_layers(drawing)++    # Library+    library = ET.SubElement(drawing, "library")++    if description:+        desc_el = ET.SubElement(library, "description")+        desc_el.text = description++    # Packages (empty — symbols only for now)+    ET.SubElement(library, "packages")++    # Symbols+    symbols_el = ET.SubElement(library, "symbols")+    for sym in symbols:+        symbols_el.append(_build_symbol_element(sym))++    # Devicesets (one per symbol, minimal — just gates mapping)+    devicesets_el = ET.SubElement(library, "devicesets")+    for sym in symbols:+        ds = ET.SubElement(devicesets_el, "deviceset",+                           name=sym["name"], prefix=sym.get("prefix", "U"))+        if sym.get("description"):+            ds_desc = ET.SubElement(ds, "description")+            ds_desc.text = sym["description"]+        gates = ET.SubElement(ds, "gates")+        ET.SubElement(gates, "gate", name="G$1", symbol=sym["name"],+                      x="0", y="0")+        ET.SubElement(ds, "devices")++    # Compatibility notes+    compat = ET.SubElement(root, "compatibility")+    note = ET.SubElement(compat, "note", version="8.3", severity="warning")+    note.text = ("Since Version 8.3, EAGLE supports URNs for individual library "+                 "assets (packages, symbols, and devices). The URNs of those assets "+                 "will not be understood (or retained) with this version.")++    # Pretty-print+    xml_str = ET.tostring(root, encoding="unicode", xml_declaration=False)+    dom = minidom.parseString(xml_str)+    pretty = dom.toprettyxml(indent="  ", encoding=None)+    # Remove the extra xml declaration minidom adds+    lines = pretty.split("\n")+    if lines[0].startswith("<?xml"):+        lines[0] = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+    return "\n".join(lines)+++def write_lbr(xml: str, path: str) -> str:+    """Write an LBR XML string to a file. Returns the path."""+    with open(path, "w", encoding="utf-8") as f:+        f.write(xml)+    return path
examples/._ADS8588SIPM.fusion.lbradded
⋯ 1 unchanged line ⋯
examples/._ADS8588SIPM.stepadded
⋯ 1 unchanged line ⋯
examples/._jst_connector_generator.pyadded
⋯ 1 unchanged line ⋯
examples/._jst_ph_connector.pyadded
⋯ 1 unchanged line ⋯
examples/ADS8588SIPM.fusion.lbradded+294
@@ -0,0 +1,294 @@+<?xml version="1.0" encoding="utf-8"?>+<!DOCTYPE eagle SYSTEM "eagle.dtd">+<eagle version="9.6.2">+<drawing>+<settings><setting alwaysvectorfont="no"/></settings>+<grid distance="0.1" unitdist="inch" unit="inch" style="lines" multiple="1" display="no" altdistance="0.01" altunitdist="inch" altunit="inch"/>+<layers>+<layer number="1" name="Top" color="4" fill="1" visible="yes" active="yes"/>+<layer number="16" name="Bottom" color="1" fill="1" visible="yes" active="yes"/>+<layer number="17" name="Pads" color="2" fill="1" visible="yes" active="yes"/>+<layer number="18" name="Vias" color="2" fill="1" visible="yes" active="yes"/>+<layer number="19" name="Unrouted" color="6" fill="1" visible="yes" active="yes"/>+<layer number="20" name="Dimension" color="15" fill="1" visible="yes" active="yes"/>+<layer number="21" name="tPlace" color="7" fill="1" visible="yes" active="yes"/>+<layer number="22" name="bPlace" color="7" fill="1" visible="yes" active="yes"/>+<layer number="23" name="tOrigins" color="15" fill="1" visible="yes" active="yes"/>+<layer number="24" name="bOrigins" color="15" fill="1" visible="yes" active="yes"/>+<layer number="25" name="tNames" color="7" fill="1" visible="yes" active="yes"/>+<layer number="26" name="bNames" color="7" fill="1" visible="yes" active="yes"/>+<layer number="27" name="tValues" color="7" fill="1" visible="yes" active="yes"/>+<layer number="28" name="bValues" color="7" fill="1" visible="yes" active="yes"/>+<layer number="29" name="tStop" color="7" fill="3" visible="no" active="yes"/>+<layer number="30" name="bStop" color="7" fill="6" visible="no" active="yes"/>+<layer number="31" name="tCream" color="7" fill="4" visible="no" active="yes"/>+<layer number="32" name="bCream" color="7" fill="5" visible="no" active="yes"/>+<layer number="33" name="tFinish" color="6" fill="3" visible="no" active="yes"/>+<layer number="34" name="bFinish" color="6" fill="6" visible="no" active="yes"/>+<layer number="35" name="tGlue" color="7" fill="4" visible="no" active="yes"/>+<layer number="36" name="bGlue" color="7" fill="5" visible="no" active="yes"/>+<layer number="37" name="tTest" color="7" fill="1" visible="no" active="yes"/>+<layer number="38" name="bTest" color="7" fill="1" visible="no" active="yes"/>+<layer number="39" name="tKeepout" color="4" fill="11" visible="no" active="yes"/>+<layer number="40" name="bKeepout" color="1" fill="11" visible="no" active="yes"/>+<layer number="41" name="tRestrict" color="4" fill="10" visible="no" active="yes"/>+<layer number="42" name="bRestrict" color="1" fill="10" visible="no" active="yes"/>+<layer number="43" name="vRestrict" color="2" fill="10" visible="no" active="yes"/>+<layer number="44" name="Drills" color="7" fill="1" visible="no" active="yes"/>+<layer number="45" name="Holes" color="7" fill="1" visible="no" active="yes"/>+<layer number="46" name="Milling" color="3" fill="1" visible="no" active="yes"/>+<layer number="47" name="Measures" color="7" fill="1" visible="no" active="yes"/>+<layer number="48" name="Document" color="7" fill="1" visible="yes" active="yes"/>+<layer number="49" name="Reference" color="7" fill="1" visible="yes" active="yes"/>+<layer number="91" name="Nets" color="2" fill="1" visible="yes" active="yes"/>+<layer number="92" name="Busses" color="1" fill="1" visible="yes" active="yes"/>+<layer number="93" name="Pins" color="2" fill="1" visible="no" active="yes"/>+<layer number="94" name="Symbols" color="4" fill="1" visible="yes" active="yes"/>+<layer number="95" name="Names" color="7" fill="1" visible="yes" active="yes"/>+<layer number="96" name="Values" color="7" fill="1" visible="yes" active="yes"/>+<layer number="97" name="Info" color="7" fill="1" visible="yes" active="yes"/>+<layer number="98" name="Guide" color="6" fill="1" visible="yes" active="yes"/>+</layers>+<library>+<description></description>+<packages>+<package name="ADS8588SIPM">+  <description>ADS8588SIPM</description>+  <smd name="1" x="-5.7380" y="3.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="2" x="-5.7380" y="3.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="3" x="-5.7380" y="2.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="4" x="-5.7380" y="2.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="5" x="-5.7380" y="1.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="6" x="-5.7380" y="1.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="7" x="-5.7380" y="0.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="8" x="-5.7380" y="0.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="9" x="-5.7380" y="-0.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="10" x="-5.7380" y="-0.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="11" x="-5.7380" y="-1.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="12" x="-5.7380" y="-1.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="13" x="-5.7380" y="-2.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="14" x="-5.7380" y="-2.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="15" x="-5.7380" y="-3.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="16" x="-5.7380" y="-3.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="17" x="-3.7500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="18" x="-3.2500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="19" x="-2.7500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="20" x="-2.2500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="21" x="-1.7500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="22" x="-1.2500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="23" x="-0.7500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="24" x="-0.2500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="25" x="0.2500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="26" x="0.7500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="27" x="1.2500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="28" x="1.7500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="29" x="2.2500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="30" x="2.7500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="31" x="3.2500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="32" x="3.7500" y="-5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="33" x="5.7380" y="-3.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="34" x="5.7380" y="-3.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="35" x="5.7380" y="-2.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="36" x="5.7380" y="-2.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="37" x="5.7380" y="-1.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="38" x="5.7380" y="-1.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="39" x="5.7380" y="-0.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="40" x="5.7380" y="-0.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="41" x="5.7380" y="0.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="42" x="5.7380" y="0.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="43" x="5.7380" y="1.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="44" x="5.7380" y="1.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="45" x="5.7380" y="2.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="46" x="5.7380" y="2.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="47" x="5.7380" y="3.2500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="48" x="5.7380" y="3.7500" dx="1.4750" dy="0.3000" layer="1"/>+  <smd name="49" x="3.7500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="50" x="3.2500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="51" x="2.7500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="52" x="2.2500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="53" x="1.7500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="54" x="1.2500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="55" x="0.7500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="56" x="0.2500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="57" x="-0.2500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="58" x="-0.7500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="59" x="-1.2500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="60" x="-1.7500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="61" x="-2.2500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="62" x="-2.7500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="63" x="-3.2500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <smd name="64" x="-3.7500" y="5.7380" dx="1.4750" dy="0.3000" layer="1" rot="R90"/>+  <wire x1="-4.6500" y1="-4.6500" x2="4.6500" y2="-4.6500" width="0.127" layer="21"/>+  <wire x1="4.6500" y1="-4.6500" x2="4.6500" y2="4.6500" width="0.127" layer="21"/>+  <wire x1="4.6500" y1="4.6500" x2="-4.6500" y2="4.6500" width="0.127" layer="21"/>+  <wire x1="-4.6500" y1="4.6500" x2="-4.6500" y2="-4.6500" width="0.127" layer="21"/>+  <text x="0" y="5.1500" size="1.27" layer="25" align="bottom-center">&gt;NAME</text>+  <text x="0" y="-5.1500" size="1.27" layer="27" align="top-center">&gt;VALUE</text>+</package>+</packages>+<packages3d>+<package3d name="ADS8588SIPM" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.AbCdEf123?version=1" locally_modified="yes" type="model">+  <packageinstances>+    <packageinstance name="ADS8588SIPM"/>+  </packageinstances>+</package3d>+</packages3d>+<symbols>+<symbol name="ADS8588SIPM">+  <wire x1="2.54" y1="22.86" x2="53.34" y2="22.86" width="0.254" layer="94"/>+  <wire x1="53.34" y1="22.86" x2="53.34" y2="-63.5" width="0.254" layer="94"/>+  <wire x1="53.34" y1="-63.5" x2="2.54" y2="-63.5" width="0.254" layer="94"/>+  <wire x1="2.54" y1="-63.5" x2="2.54" y2="22.86" width="0.254" layer="94"/>+  <text x="0" y="25.4" size="1.27" layer="95" align="bottom-center">&gt;NAME</text>+  <text x="0" y="-66.04" size="1.27" layer="96" align="top-center">&gt;VALUE</text>+  <pin name="AVDD_1" x="0" y="0" length="middle" direction="io"/>+  <pin name="AGND_1" x="0" y="-2.54" length="middle" direction="io"/>+  <pin name="OS0" x="0" y="-5.08" length="middle" direction="io"/>+  <pin name="OS1" x="0" y="-7.62" length="middle" direction="io"/>+  <pin name="OS2" x="0" y="-10.16" length="middle" direction="io"/>+  <pin name="!PAR!/SER/BYTE_SEL" x="0" y="-12.7" length="middle" direction="io"/>+  <pin name="!STBY" x="0" y="-15.24" length="middle" direction="io"/>+  <pin name="RANGE" x="0" y="-17.78" length="middle" direction="io"/>+  <pin name="CONVSTA" x="0" y="-20.32" length="middle" direction="io"/>+  <pin name="CONVSTB" x="0" y="-22.86" length="middle" direction="io"/>+  <pin name="RESET" x="0" y="-25.4" length="middle" direction="io"/>+  <pin name="!RD!/SCLK" x="0" y="-27.94" length="middle" direction="io"/>+  <pin name="!CS" x="0" y="-30.48" length="middle" direction="io"/>+  <pin name="BUSY" x="0" y="-33.02" length="middle" direction="io"/>+  <pin name="FRSTDATA" x="0" y="-35.56" length="middle" direction="io"/>+  <pin name="DB0" x="0" y="-38.1" length="middle" direction="io"/>+  <pin name="DB1" x="7.62" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DB2" x="10.16" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DB3" x="12.7" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DB4" x="15.24" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DB5" x="17.78" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DB6" x="20.32" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DVDD" x="22.86" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DB7/DOUTA" x="25.4" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DB8/DOUTB" x="27.94" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="AGND_2" x="30.48" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DB9" x="33.02" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DB10" x="35.56" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DB11" x="38.1" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DB12" x="40.64" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DB13" x="43.18" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="DB14/HBEN" x="45.72" y="-60.96" length="middle" direction="io" rot="R90"/>+  <pin name="AVDD_4" x="55.88" y="0" length="middle" direction="io" rot="R180"/>+  <pin name="AGND_6" x="55.88" y="-2.54" length="middle" direction="io" rot="R180"/>+  <pin name="REFGND_2" x="55.88" y="-5.08" length="middle" direction="io" rot="R180"/>+  <pin name="REFCAPB" x="55.88" y="-7.62" length="middle" direction="io" rot="R180"/>+  <pin name="REFCAPA" x="55.88" y="-10.16" length="middle" direction="io" rot="R180"/>+  <pin name="REFGND_1" x="55.88" y="-12.7" length="middle" direction="io" rot="R180"/>+  <pin name="REFIN/REFOUT" x="55.88" y="-15.24" length="middle" direction="io" rot="R180"/>+  <pin name="AGND_5" x="55.88" y="-17.78" length="middle" direction="io" rot="R180"/>+  <pin name="AGND_4" x="55.88" y="-20.32" length="middle" direction="io" rot="R180"/>+  <pin name="REGCAP2" x="55.88" y="-22.86" length="middle" direction="io" rot="R180"/>+  <pin name="AVDD_3" x="55.88" y="-25.4" length="middle" direction="io" rot="R180"/>+  <pin name="AVDD_2" x="55.88" y="-27.94" length="middle" direction="io" rot="R180"/>+  <pin name="REGCAP1" x="55.88" y="-30.48" length="middle" direction="io" rot="R180"/>+  <pin name="AGND_3" x="55.88" y="-33.02" length="middle" direction="io" rot="R180"/>+  <pin name="REFSEL" x="55.88" y="-35.56" length="middle" direction="io" rot="R180"/>+  <pin name="DB15/BYTE_SEL" x="55.88" y="-38.1" length="middle" direction="io" rot="R180"/>+  <pin name="AIN_8GND" x="7.62" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_8P" x="10.16" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_7GND" x="12.7" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_7P" x="15.24" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_6GND" x="17.78" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_6P" x="20.32" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_5GND" x="22.86" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_5P" x="25.4" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_4GND" x="27.94" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_4P" x="30.48" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_3GND" x="33.02" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_3P" x="35.56" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_2GND" x="38.1" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_2P" x="40.64" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_1GND" x="43.18" y="20.32" length="middle" direction="io" rot="R270"/>+  <pin name="AIN_1P" x="45.72" y="20.32" length="middle" direction="io" rot="R270"/>+</symbol>+</symbols>+<devicesets>+<deviceset name="ADS8588SIPM" prefix="U">+  <description></description>+  <gates>+    <gate name="G$1" symbol="ADS8588SIPM" x="0" y="0"/>+  </gates>+  <devices>+    <device name="" package="ADS8588SIPM">+      <connects>+        <connect gate="G$1" pin="AVDD_1" pad="1"/>+        <connect gate="G$1" pin="AGND_1" pad="2"/>+        <connect gate="G$1" pin="OS0" pad="3"/>+        <connect gate="G$1" pin="OS1" pad="4"/>+        <connect gate="G$1" pin="OS2" pad="5"/>+        <connect gate="G$1" pin="!PAR!/SER/BYTE_SEL" pad="6"/>+        <connect gate="G$1" pin="!STBY" pad="7"/>+        <connect gate="G$1" pin="RANGE" pad="8"/>+        <connect gate="G$1" pin="CONVSTA" pad="9"/>+        <connect gate="G$1" pin="CONVSTB" pad="10"/>+        <connect gate="G$1" pin="RESET" pad="11"/>+        <connect gate="G$1" pin="!RD!/SCLK" pad="12"/>+        <connect gate="G$1" pin="!CS" pad="13"/>+        <connect gate="G$1" pin="BUSY" pad="14"/>+        <connect gate="G$1" pin="FRSTDATA" pad="15"/>+        <connect gate="G$1" pin="DB0" pad="16"/>+        <connect gate="G$1" pin="DB1" pad="17"/>+        <connect gate="G$1" pin="DB2" pad="18"/>+        <connect gate="G$1" pin="DB3" pad="19"/>+        <connect gate="G$1" pin="DB4" pad="20"/>+        <connect gate="G$1" pin="DB5" pad="21"/>+        <connect gate="G$1" pin="DB6" pad="22"/>+        <connect gate="G$1" pin="DVDD" pad="23"/>+        <connect gate="G$1" pin="DB7/DOUTA" pad="24"/>+        <connect gate="G$1" pin="DB8/DOUTB" pad="25"/>+        <connect gate="G$1" pin="AGND_2" pad="26"/>+        <connect gate="G$1" pin="DB9" pad="27"/>+        <connect gate="G$1" pin="DB10" pad="28"/>+        <connect gate="G$1" pin="DB11" pad="29"/>+        <connect gate="G$1" pin="DB12" pad="30"/>+        <connect gate="G$1" pin="DB13" pad="31"/>+        <connect gate="G$1" pin="DB14/HBEN" pad="32"/>+        <connect gate="G$1" pin="AVDD_4" pad="48"/>+        <connect gate="G$1" pin="AGND_6" pad="47"/>+        <connect gate="G$1" pin="REFGND_2" pad="46"/>+        <connect gate="G$1" pin="REFCAPB" pad="45"/>+        <connect gate="G$1" pin="REFCAPA" pad="44"/>+        <connect gate="G$1" pin="REFGND_1" pad="43"/>+        <connect gate="G$1" pin="REFIN/REFOUT" pad="42"/>+        <connect gate="G$1" pin="AGND_5" pad="41"/>+        <connect gate="G$1" pin="AGND_4" pad="40"/>+        <connect gate="G$1" pin="REGCAP2" pad="39"/>+        <connect gate="G$1" pin="AVDD_3" pad="38"/>+        <connect gate="G$1" pin="AVDD_2" pad="37"/>+        <connect gate="G$1" pin="REGCAP1" pad="36"/>+        <connect gate="G$1" pin="AGND_3" pad="35"/>+        <connect gate="G$1" pin="REFSEL" pad="34"/>+        <connect gate="G$1" pin="DB15/BYTE_SEL" pad="33"/>+        <connect gate="G$1" pin="AIN_8GND" pad="64"/>+        <connect gate="G$1" pin="AIN_8P" pad="63"/>+        <connect gate="G$1" pin="AIN_7GND" pad="62"/>+        <connect gate="G$1" pin="AIN_7P" pad="61"/>+        <connect gate="G$1" pin="AIN_6GND" pad="60"/>+        <connect gate="G$1" pin="AIN_6P" pad="59"/>+        <connect gate="G$1" pin="AIN_5GND" pad="58"/>+        <connect gate="G$1" pin="AIN_5P" pad="57"/>+        <connect gate="G$1" pin="AIN_4GND" pad="56"/>+        <connect gate="G$1" pin="AIN_4P" pad="55"/>+        <connect gate="G$1" pin="AIN_3GND" pad="54"/>+        <connect gate="G$1" pin="AIN_3P" pad="53"/>+        <connect gate="G$1" pin="AIN_2GND" pad="52"/>+        <connect gate="G$1" pin="AIN_2P" pad="51"/>+        <connect gate="G$1" pin="AIN_1GND" pad="50"/>+        <connect gate="G$1" pin="AIN_1P" pad="49"/>+      </connects>+      <package3dinstances>+        <package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.AbCdEf123?version=1"/>+      </package3dinstances>+      <technologies><technology name=""/></technologies>+    </device>+  </devices>+</deviceset>+</devicesets>+</library>+</drawing>+</eagle>\ No newline at end of file
examples/ADS8588SIPM.stepadded+4880
@@ -0,0 +1,4880 @@+ISO-10303-21;
+HEADER;
+FILE_DESCRIPTION((''),'2;1');
+FILE_NAME('PM0064A_ASM','2017-03-03T',('a0412025'),(''),
+'CREO PARAMETRIC BY PTC INC, 2016050','CREO PARAMETRIC BY PTC INC, 2016050','');
+FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }'));
+ENDSEC;
+DATA;
+#28=CARTESIAN_POINT('',(-4.3E0,6.35E-1,-4.3E0));
+#29=DIRECTION('',(0.E0,-1.E0,0.E0));
+#30=DIRECTION('',(1.E0,0.E0,0.E0));
+#31=AXIS2_PLACEMENT_3D('',#28,#29,#30);
+#33=DRAUGHTING_PRE_DEFINED_CURVE_FONT('continuous');
+#34=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#35=PRESENTATION_STYLE_ASSIGNMENT((#34));
+#36=STYLED_ITEM('',(#35),#32);
+#37=CARTESIAN_POINT('',(-4.3E0,6.35E-1,-4.3E0));
+#38=DIRECTION('',(0.E0,-1.E0,0.E0));
+#39=DIRECTION('',(-1.E0,0.E0,0.E0));
+#40=AXIS2_PLACEMENT_3D('',#37,#38,#39);
+#42=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#43=PRESENTATION_STYLE_ASSIGNMENT((#42));
+#44=STYLED_ITEM('',(#43),#41);
+#45=DIRECTION('',(-1.E0,0.E0,0.E0));
+#46=VECTOR('',#45,9.202115990712E0);
+#47=CARTESIAN_POINT('',(4.601057995356E0,6.35E-1,-4.833559277371E0));
+#48=LINE('',#47,#46);
+#49=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#50=PRESENTATION_STYLE_ASSIGNMENT((#49));
+#51=STYLED_ITEM('',(#50),#48);
+#52=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#53=VECTOR('',#52,3.288064662950E-1);
+#54=CARTESIAN_POINT('',(4.833559277371E0,6.35E-1,-4.601057995356E0));
+#55=LINE('',#54,#53);
+#56=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#57=PRESENTATION_STYLE_ASSIGNMENT((#56));
+#58=STYLED_ITEM('',(#57),#55);
+#59=DIRECTION('',(0.E0,0.E0,-1.E0));
+#60=VECTOR('',#59,9.202115990712E0);
+#61=CARTESIAN_POINT('',(4.833559277371E0,6.35E-1,4.601057995356E0));
+#62=LINE('',#61,#60);
+#63=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#64=PRESENTATION_STYLE_ASSIGNMENT((#63));
+#65=STYLED_ITEM('',(#64),#62);
+#66=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#67=VECTOR('',#66,3.288064662950E-1);
+#68=CARTESIAN_POINT('',(4.601057995356E0,6.35E-1,4.833559277371E0));
+#69=LINE('',#68,#67);
+#70=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#71=PRESENTATION_STYLE_ASSIGNMENT((#70));
+#72=STYLED_ITEM('',(#71),#69);
+#73=DIRECTION('',(1.E0,0.E0,0.E0));
+#74=VECTOR('',#73,9.202115990712E0);
+#75=CARTESIAN_POINT('',(-4.601057995356E0,6.35E-1,4.833559277371E0));
+#76=LINE('',#75,#74);
+#77=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#78=PRESENTATION_STYLE_ASSIGNMENT((#77));
+#79=STYLED_ITEM('',(#78),#76);
+#80=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#81=VECTOR('',#80,3.288064662950E-1);
+#82=CARTESIAN_POINT('',(-4.833559277371E0,6.35E-1,4.601057995356E0));
+#83=LINE('',#82,#81);
+#84=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#85=PRESENTATION_STYLE_ASSIGNMENT((#84));
+#86=STYLED_ITEM('',(#85),#83);
+#87=DIRECTION('',(0.E0,0.E0,1.E0));
+#88=VECTOR('',#87,9.202115990712E0);
+#89=CARTESIAN_POINT('',(-4.833559277371E0,6.35E-1,-4.601057995356E0));
+#90=LINE('',#89,#88);
+#91=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#92=PRESENTATION_STYLE_ASSIGNMENT((#91));
+#93=STYLED_ITEM('',(#92),#90);
+#94=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#95=VECTOR('',#94,3.288064662950E-1);
+#96=CARTESIAN_POINT('',(-4.601057995356E0,6.35E-1,-4.833559277371E0));
+#97=LINE('',#96,#95);
+#98=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#99=PRESENTATION_STYLE_ASSIGNMENT((#98));
+#100=STYLED_ITEM('',(#99),#97);
+#101=DIRECTION('',(0.E0,-1.E0,0.E0));
+#102=VECTOR('',#101,5.E-2);
+#103=CARTESIAN_POINT('',(-4.05E0,6.35E-1,-4.3E0));
+#104=LINE('',#103,#102);
+#105=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#106=PRESENTATION_STYLE_ASSIGNMENT((#105));
+#107=STYLED_ITEM('',(#106),#104);
+#108=DIRECTION('',(0.E0,-1.E0,0.E0));
+#109=VECTOR('',#108,5.E-2);
+#110=CARTESIAN_POINT('',(-4.55E0,6.35E-1,-4.3E0));
+#111=LINE('',#110,#109);
+#112=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#113=PRESENTATION_STYLE_ASSIGNMENT((#112));
+#114=STYLED_ITEM('',(#113),#111);
+#115=CARTESIAN_POINT('',(-4.3E0,5.85E-1,-4.3E0));
+#116=DIRECTION('',(0.E0,-1.E0,0.E0));
+#117=DIRECTION('',(1.E0,0.E0,0.E0));
+#118=AXIS2_PLACEMENT_3D('',#115,#116,#117);
+#120=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#121=PRESENTATION_STYLE_ASSIGNMENT((#120));
+#122=STYLED_ITEM('',(#121),#119);
+#123=CARTESIAN_POINT('',(-4.3E0,5.85E-1,-4.3E0));
+#124=DIRECTION('',(0.E0,-1.E0,0.E0));
+#125=DIRECTION('',(-1.E0,0.E0,0.E0));
+#126=AXIS2_PLACEMENT_3D('',#123,#124,#125);
+#128=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#129=PRESENTATION_STYLE_ASSIGNMENT((#128));
+#130=STYLED_ITEM('',(#129),#127);
+#131=DIRECTION('',(-1.E0,0.E0,0.E0));
+#132=VECTOR('',#131,9.202115990712E0);
+#133=CARTESIAN_POINT('',(4.601057995356E0,5.471869343405E-1,-4.932813892535E0));
+#134=LINE('',#133,#132);
+#135=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#136=PRESENTATION_STYLE_ASSIGNMENT((#135));
+#137=STYLED_ITEM('',(#136),#134);
+#138=DIRECTION('',(5.013678097069E-2,9.912978866622E-1,1.217160757378E-1));
+#139=VECTOR('',#138,5.519904175151E-1);
+#140=CARTESIAN_POINT('',(-4.628733018017E0,-1.384388157703E-14,-5.E0));
+#141=LINE('',#140,#139);
+#142=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#143=PRESENTATION_STYLE_ASSIGNMENT((#142));
+#144=STYLED_ITEM('',(#143),#141);
+#145=DIRECTION('',(1.E0,0.E0,0.E0));
+#146=VECTOR('',#145,9.257466036034E0);
+#147=CARTESIAN_POINT('',(-4.628733018017E0,-1.384388157703E-14,-5.E0));
+#148=LINE('',#147,#146);
+#149=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#150=PRESENTATION_STYLE_ASSIGNMENT((#149));
+#151=STYLED_ITEM('',(#150),#148);
+#152=DIRECTION('',(5.013678097070E-2,-9.912978866622E-1,-1.217160757378E-1));
+#153=VECTOR('',#152,5.519904175151E-1);
+#154=CARTESIAN_POINT('',(4.601057995356E0,5.471869343405E-1,-4.932813892535E0));
+#155=LINE('',#154,#153);
+#156=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#157=PRESENTATION_STYLE_ASSIGNMENT((#156));
+#158=STYLED_ITEM('',(#157),#155);
+#159=DIRECTION('',(5.061420472237E-2,9.912978866622E-1,1.215183203448E-1));
+#160=VECTOR('',#159,5.519904175151E-1);
+#161=CARTESIAN_POINT('',(-4.699180162799E0,0.E0,-4.970819837201E0));
+#162=LINE('',#161,#160);
+#163=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#164=PRESENTATION_STYLE_ASSIGNMENT((#163));
+#165=STYLED_ITEM('',(#164),#162);
+#166=DIRECTION('',(-7.071067811866E-1,0.E0,7.071067811865E-1));
+#167=VECTOR('',#166,3.288064662950E-1);
+#168=CARTESIAN_POINT('',(-4.671241606803E0,5.471869343405E-1,
+-4.903742888818E0));
+#169=LINE('',#168,#167);
+#170=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#171=PRESENTATION_STYLE_ASSIGNMENT((#170));
+#172=STYLED_ITEM('',(#171),#169);
+#173=DIRECTION('',(-1.215183203448E-1,-9.912978866622E-1,-5.061420472236E-2));
+#174=VECTOR('',#173,5.519904175151E-1);
+#175=CARTESIAN_POINT('',(-4.903742888818E0,5.471869343405E-1,
+-4.671241606803E0));
+#176=LINE('',#175,#174);
+#177=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#178=PRESENTATION_STYLE_ASSIGNMENT((#177));
+#179=STYLED_ITEM('',(#178),#176);
+#180=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#181=VECTOR('',#180,3.841565116167E-1);
+#182=CARTESIAN_POINT('',(-4.699180162799E0,0.E0,-4.970819837201E0));
+#183=LINE('',#182,#181);
+#184=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#185=PRESENTATION_STYLE_ASSIGNMENT((#184));
+#186=STYLED_ITEM('',(#185),#183);
+#187=CARTESIAN_POINT('',(-4.833559277371E0,5.35E-1,-4.601057995356E0));
+#188=DIRECTION('',(1.217143643511E-1,9.912839485362E-1,5.041574044985E-2));
+#189=DIRECTION('',(-7.018361144662E-1,1.218693434051E-1,-7.018361144662E-1));
+#190=AXIS2_PLACEMENT_3D('',#187,#188,#189);
+#192=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#193=PRESENTATION_STYLE_ASSIGNMENT((#192));
+#194=STYLED_ITEM('',(#193),#191);
+#195=CARTESIAN_POINT('',(-4.833559277371E0,5.35E-1,-4.601057995356E0));
+#196=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#197=DIRECTION('',(0.E0,1.E0,0.E0));
+#198=AXIS2_PLACEMENT_3D('',#195,#196,#197);
+#200=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#201=PRESENTATION_STYLE_ASSIGNMENT((#200));
+#202=STYLED_ITEM('',(#201),#199);
+#203=CARTESIAN_POINT('',(-4.833559277371E0,5.35E-1,-4.601057995356E0));
+#204=DIRECTION('',(0.E0,0.E0,-1.E0));
+#205=DIRECTION('',(-9.925461516413E-1,1.218693434051E-1,0.E0));
+#206=AXIS2_PLACEMENT_3D('',#203,#204,#205);
+#208=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#209=PRESENTATION_STYLE_ASSIGNMENT((#208));
+#210=STYLED_ITEM('',(#209),#207);
+#211=CARTESIAN_POINT('',(-4.970819837201E0,0.E0,-4.699180162799E0));
+#212=CARTESIAN_POINT('',(-4.976872408249E0,0.E0,-4.693127591751E0));
+#213=CARTESIAN_POINT('',(-4.987581634393E0,5.905908534353E-4,
+-4.679186988847E0));
+#214=CARTESIAN_POINT('',(-4.997715071581E0,5.905908534543E-4,
+-4.654722707355E0));
+#215=CARTESIAN_POINT('',(-5.E0,0.E0,-4.637292646081E0));
+#216=CARTESIAN_POINT('',(-5.E0,0.E0,-4.628733018017E0));
+#218=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#219=PRESENTATION_STYLE_ASSIGNMENT((#218));
+#220=STYLED_ITEM('',(#219),#217);
+#221=DIRECTION('',(0.E0,0.E0,1.E0));
+#222=VECTOR('',#221,9.202115990712E0);
+#223=CARTESIAN_POINT('',(-4.932813892535E0,5.471869343405E-1,
+-4.601057995356E0));
+#224=LINE('',#223,#222);
+#225=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#226=PRESENTATION_STYLE_ASSIGNMENT((#225));
+#227=STYLED_ITEM('',(#226),#224);
+#228=DIRECTION('',(1.217160757378E-1,9.912978866622E-1,-5.013678097069E-2));
+#229=VECTOR('',#228,5.519904175151E-1);
+#230=CARTESIAN_POINT('',(-5.E0,0.E0,4.628733018017E0));
+#231=LINE('',#230,#229);
+#232=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#233=PRESENTATION_STYLE_ASSIGNMENT((#232));
+#234=STYLED_ITEM('',(#233),#231);
+#235=DIRECTION('',(0.E0,0.E0,-1.E0));
+#236=VECTOR('',#235,9.257466036034E0);
+#237=CARTESIAN_POINT('',(-5.E0,0.E0,4.628733018017E0));
+#238=LINE('',#237,#236);
+#239=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#240=PRESENTATION_STYLE_ASSIGNMENT((#239));
+#241=STYLED_ITEM('',(#240),#238);
+#242=DIRECTION('',(-1.217160757378E-1,-9.912978866622E-1,-5.013678097070E-2));
+#243=VECTOR('',#242,5.519904175151E-1);
+#244=CARTESIAN_POINT('',(-4.932813892535E0,5.471869343405E-1,
+-4.601057995356E0));
+#245=LINE('',#244,#243);
+#246=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#247=PRESENTATION_STYLE_ASSIGNMENT((#246));
+#248=STYLED_ITEM('',(#247),#245);
+#249=CARTESIAN_POINT('',(-4.833559277371E0,5.35E-1,4.601057995356E0));
+#250=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#251=DIRECTION('',(-7.018361144662E-1,1.218693434051E-1,7.018361144662E-1));
+#252=AXIS2_PLACEMENT_3D('',#249,#250,#251);
+#254=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#255=PRESENTATION_STYLE_ASSIGNMENT((#254));
+#256=STYLED_ITEM('',(#255),#253);
+#257=CARTESIAN_POINT('',(-4.833559277371E0,5.35E-1,4.601057995356E0));
+#258=DIRECTION('',(1.217143643511E-1,9.912839485362E-1,-5.041574044985E-2));
+#259=DIRECTION('',(-9.925461516413E-1,1.218693434051E-1,0.E0));
+#260=AXIS2_PLACEMENT_3D('',#257,#258,#259);
+#262=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#263=PRESENTATION_STYLE_ASSIGNMENT((#262));
+#264=STYLED_ITEM('',(#263),#261);
+#265=CARTESIAN_POINT('',(-4.833559277371E0,5.35E-1,4.601057995356E0));
+#266=DIRECTION('',(0.E0,0.E0,1.E0));
+#267=DIRECTION('',(0.E0,1.E0,0.E0));
+#268=AXIS2_PLACEMENT_3D('',#265,#266,#267);
+#270=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#271=PRESENTATION_STYLE_ASSIGNMENT((#270));
+#272=STYLED_ITEM('',(#271),#269);
+#273=DIRECTION('',(1.215183203448E-1,9.912978866622E-1,-5.061420472237E-2));
+#274=VECTOR('',#273,5.519904175151E-1);
+#275=CARTESIAN_POINT('',(-4.970819837201E0,1.704336290632E-14,
+4.699180162799E0));
+#276=LINE('',#275,#274);
+#277=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#278=PRESENTATION_STYLE_ASSIGNMENT((#277));
+#279=STYLED_ITEM('',(#278),#276);
+#280=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#281=VECTOR('',#280,3.288064662950E-1);
+#282=CARTESIAN_POINT('',(-4.903742888818E0,5.471869343405E-1,4.671241606803E0));
+#283=LINE('',#282,#281);
+#284=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#285=PRESENTATION_STYLE_ASSIGNMENT((#284));
+#286=STYLED_ITEM('',(#285),#283);
+#287=DIRECTION('',(-5.061420472236E-2,-9.912978866622E-1,1.215183203448E-1));
+#288=VECTOR('',#287,5.519904175151E-1);
+#289=CARTESIAN_POINT('',(-4.671241606803E0,5.471869343405E-1,4.903742888818E0));
+#290=LINE('',#289,#288);
+#291=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#292=PRESENTATION_STYLE_ASSIGNMENT((#291));
+#293=STYLED_ITEM('',(#292),#290);
+#294=DIRECTION('',(7.071067811865E-1,-1.360840128689E-14,7.071067811865E-1));
+#295=VECTOR('',#294,3.841565116167E-1);
+#296=CARTESIAN_POINT('',(-4.970819837201E0,1.704336290632E-14,
+4.699180162799E0));
+#297=LINE('',#296,#295);
+#298=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#299=PRESENTATION_STYLE_ASSIGNMENT((#298));
+#300=STYLED_ITEM('',(#299),#297);
+#301=CARTESIAN_POINT('',(-4.970819837201E0,1.704336290632E-14,
+4.699180162799E0));
+#302=CARTESIAN_POINT('',(-4.976985605690E0,1.703541929528E-14,
+4.693014394310E0));
+#303=CARTESIAN_POINT('',(-4.987536217203E0,5.906705500198E-4,4.679246421655E0));
+#304=CARTESIAN_POINT('',(-4.997724982119E0,5.906705500315E-4,4.654648567211E0));
+#305=CARTESIAN_POINT('',(-5.E0,0.E0,4.637452731437E0));
+#306=CARTESIAN_POINT('',(-5.E0,0.E0,4.628733018017E0));
+#308=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#309=PRESENTATION_STYLE_ASSIGNMENT((#308));
+#310=STYLED_ITEM('',(#309),#307);
+#311=DIRECTION('',(0.E0,-1.E0,1.366428338E-14));
+#312=VECTOR('',#311,1.3E-1);
+#313=CARTESIAN_POINT('',(-5.E0,0.E0,4.628733018017E0));
+#314=LINE('',#313,#312);
+#315=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#316=PRESENTATION_STYLE_ASSIGNMENT((#315));
+#317=STYLED_ITEM('',(#316),#314);
+#318=DIRECTION('',(0.E0,0.E0,1.E0));
+#319=VECTOR('',#318,9.257466036034E0);
+#320=CARTESIAN_POINT('',(-5.E0,-1.3E-1,-4.628733018017E0));
+#321=LINE('',#320,#319);
+#322=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#323=PRESENTATION_STYLE_ASSIGNMENT((#322));
+#324=STYLED_ITEM('',(#323),#321);
+#325=DIRECTION('',(0.E0,-1.E0,0.E0));
+#326=VECTOR('',#325,1.3E-1);
+#327=CARTESIAN_POINT('',(-5.E0,0.E0,-4.628733018017E0));
+#328=LINE('',#327,#326);
+#329=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#330=PRESENTATION_STYLE_ASSIGNMENT((#329));
+#331=STYLED_ITEM('',(#330),#328);
+#332=DIRECTION('',(1.217160757378E-1,-9.912978866622E-1,-5.013678097069E-2));
+#333=VECTOR('',#332,5.519904175151E-1);
+#334=CARTESIAN_POINT('',(-5.E0,-1.3E-1,4.628733018017E0));
+#335=LINE('',#334,#333);
+#336=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#337=PRESENTATION_STYLE_ASSIGNMENT((#336));
+#338=STYLED_ITEM('',(#337),#335);
+#339=DIRECTION('',(0.E0,0.E0,-1.E0));
+#340=VECTOR('',#339,9.202115990712E0);
+#341=CARTESIAN_POINT('',(-4.932813892535E0,-6.771869343405E-1,
+4.601057995356E0));
+#342=LINE('',#341,#340);
+#343=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#344=PRESENTATION_STYLE_ASSIGNMENT((#343));
+#345=STYLED_ITEM('',(#344),#342);
+#346=DIRECTION('',(1.217160757378E-1,-9.912978866622E-1,5.013678097070E-2));
+#347=VECTOR('',#346,5.519904175151E-1);
+#348=CARTESIAN_POINT('',(-5.E0,-1.3E-1,-4.628733018017E0));
+#349=LINE('',#348,#347);
+#350=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#351=PRESENTATION_STYLE_ASSIGNMENT((#350));
+#352=STYLED_ITEM('',(#351),#349);
+#353=CARTESIAN_POINT('',(-4.970819837201E0,-1.3E-1,4.699180162799E0));
+#354=CARTESIAN_POINT('',(-4.976872408249E0,-1.3E-1,4.693127591751E0));
+#355=CARTESIAN_POINT('',(-4.987581634393E0,-1.305905908535E-1,
+4.679186988847E0));
+#356=CARTESIAN_POINT('',(-4.997715071581E0,-1.305905908535E-1,
+4.654722707355E0));
+#357=CARTESIAN_POINT('',(-5.E0,-1.3E-1,4.637292646081E0));
+#358=CARTESIAN_POINT('',(-5.E0,-1.3E-1,4.628733018017E0));
+#360=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#361=PRESENTATION_STYLE_ASSIGNMENT((#360));
+#362=STYLED_ITEM('',(#361),#359);
+#363=DIRECTION('',(1.215183203449E-1,-9.912978866622E-1,-5.061420472236E-2));
+#364=VECTOR('',#363,5.519904175151E-1);
+#365=CARTESIAN_POINT('',(-4.970819837201E0,-1.3E-1,4.699180162799E0));
+#366=LINE('',#365,#364);
+#367=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#368=PRESENTATION_STYLE_ASSIGNMENT((#367));
+#369=STYLED_ITEM('',(#368),#366);
+#370=DIRECTION('',(5.061420472237E-2,-9.912978866622E-1,-1.215183203448E-1));
+#371=VECTOR('',#370,5.519904175151E-1);
+#372=CARTESIAN_POINT('',(-4.699180162799E0,-1.3E-1,4.970819837201E0));
+#373=LINE('',#372,#371);
+#374=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#375=PRESENTATION_STYLE_ASSIGNMENT((#374));
+#376=STYLED_ITEM('',(#375),#373);
+#377=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#378=VECTOR('',#377,3.288064662950E-1);
+#379=CARTESIAN_POINT('',(-4.671241606803E0,-6.771869343405E-1,
+4.903742888818E0));
+#380=LINE('',#379,#378);
+#381=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#382=PRESENTATION_STYLE_ASSIGNMENT((#381));
+#383=STYLED_ITEM('',(#382),#380);
+#384=DIRECTION('',(2.049642507E-14,-1.E0,0.E0));
+#385=VECTOR('',#384,1.3E-1);
+#386=CARTESIAN_POINT('',(-4.970819837201E0,1.704336290632E-14,
+4.699180162799E0));
+#387=LINE('',#386,#385);
+#388=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#389=PRESENTATION_STYLE_ASSIGNMENT((#388));
+#390=STYLED_ITEM('',(#389),#387);
+#391=DIRECTION('',(0.E0,-1.E0,0.E0));
+#392=VECTOR('',#391,1.3E-1);
+#393=CARTESIAN_POINT('',(-4.699180162799E0,1.181560693926E-14,
+4.970819837201E0));
+#394=LINE('',#393,#392);
+#395=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#396=PRESENTATION_STYLE_ASSIGNMENT((#395));
+#397=STYLED_ITEM('',(#396),#394);
+#398=DIRECTION('',(7.071067811865E-1,2.413173270604E-14,7.071067811865E-1));
+#399=VECTOR('',#398,3.841565116167E-1);
+#400=CARTESIAN_POINT('',(-4.970819837201E0,-1.3E-1,4.699180162799E0));
+#401=LINE('',#400,#399);
+#402=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#403=PRESENTATION_STYLE_ASSIGNMENT((#402));
+#404=STYLED_ITEM('',(#403),#401);
+#405=CARTESIAN_POINT('',(-4.699180162799E0,-1.3E-1,4.970819837201E0));
+#406=CARTESIAN_POINT('',(-4.693014394310E0,-1.3E-1,4.976985605690E0));
+#407=CARTESIAN_POINT('',(-4.679246421655E0,-1.305906705500E-1,
+4.987536217203E0));
+#408=CARTESIAN_POINT('',(-4.654648567211E0,-1.305906705500E-1,
+4.997724982119E0));
+#409=CARTESIAN_POINT('',(-4.637452731437E0,-1.3E-1,5.E0));
+#410=CARTESIAN_POINT('',(-4.628733018017E0,-1.3E-1,5.E0));
+#412=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#413=PRESENTATION_STYLE_ASSIGNMENT((#412));
+#414=STYLED_ITEM('',(#413),#411);
+#415=CARTESIAN_POINT('',(-4.699180162799E0,1.181560693926E-14,
+4.970819837201E0));
+#416=CARTESIAN_POINT('',(-4.693127591751E0,1.107481839484E-14,
+4.976872408249E0));
+#417=CARTESIAN_POINT('',(-4.679186988847E0,5.905908534736E-4,4.987581634393E0));
+#418=CARTESIAN_POINT('',(-4.654722707355E0,5.905908534517E-4,4.997715071581E0));
+#419=CARTESIAN_POINT('',(-4.637292646081E0,1.377393240095E-14,5.E0));
+#420=CARTESIAN_POINT('',(-4.628733018017E0,1.407937200784E-14,5.E0));
+#422=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#423=PRESENTATION_STYLE_ASSIGNMENT((#422));
+#424=STYLED_ITEM('',(#423),#421);
+#425=CARTESIAN_POINT('',(-4.601057995356E0,5.35E-1,4.833559277371E0));
+#426=DIRECTION('',(5.041574044985E-2,9.912839485362E-1,-1.217143643511E-1));
+#427=DIRECTION('',(-7.018361144662E-1,1.218693434051E-1,7.018361144662E-1));
+#428=AXIS2_PLACEMENT_3D('',#425,#426,#427);
+#430=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#431=PRESENTATION_STYLE_ASSIGNMENT((#430));
+#432=STYLED_ITEM('',(#431),#429);
+#433=CARTESIAN_POINT('',(-4.601057995356E0,5.35E-1,4.833559277371E0));
+#434=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#435=DIRECTION('',(0.E0,1.E0,0.E0));
+#436=AXIS2_PLACEMENT_3D('',#433,#434,#435);
+#438=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#439=PRESENTATION_STYLE_ASSIGNMENT((#438));
+#440=STYLED_ITEM('',(#439),#437);
+#441=CARTESIAN_POINT('',(-4.601057995356E0,5.35E-1,4.833559277371E0));
+#442=DIRECTION('',(-1.E0,0.E0,0.E0));
+#443=DIRECTION('',(0.E0,1.218693434051E-1,9.925461516413E-1));
+#444=AXIS2_PLACEMENT_3D('',#441,#442,#443);
+#446=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#447=PRESENTATION_STYLE_ASSIGNMENT((#446));
+#448=STYLED_ITEM('',(#447),#445);
+#449=DIRECTION('',(-5.013678097069E-2,9.912978866622E-1,-1.217160757378E-1));
+#450=VECTOR('',#449,5.519904175151E-1);
+#451=CARTESIAN_POINT('',(4.628733018017E0,1.394331102654E-14,5.E0));
+#452=LINE('',#451,#450);
+#453=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#454=PRESENTATION_STYLE_ASSIGNMENT((#453));
+#455=STYLED_ITEM('',(#454),#452);
+#456=DIRECTION('',(1.E0,0.E0,0.E0));
+#457=VECTOR('',#456,9.257466036034E0);
+#458=CARTESIAN_POINT('',(-4.628733018017E0,1.407937200784E-14,5.E0));
+#459=LINE('',#458,#457);
+#460=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#461=PRESENTATION_STYLE_ASSIGNMENT((#460));
+#462=STYLED_ITEM('',(#461),#459);
+#463=DIRECTION('',(-5.013678097069E-2,-9.912978866622E-1,1.217160757378E-1));
+#464=VECTOR('',#463,5.519904175151E-1);
+#465=CARTESIAN_POINT('',(-4.601057995356E0,5.471869343405E-1,4.932813892535E0));
+#466=LINE('',#465,#464);
+#467=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#468=PRESENTATION_STYLE_ASSIGNMENT((#467));
+#469=STYLED_ITEM('',(#468),#466);
+#470=DIRECTION('',(1.E0,0.E0,0.E0));
+#471=VECTOR('',#470,9.202115990712E0);
+#472=CARTESIAN_POINT('',(-4.601057995356E0,5.471869343405E-1,4.932813892535E0));
+#473=LINE('',#472,#471);
+#474=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#475=PRESENTATION_STYLE_ASSIGNMENT((#474));
+#476=STYLED_ITEM('',(#475),#473);
+#477=DIRECTION('',(7.071067811866E-1,0.E0,-7.071067811865E-1));
+#478=VECTOR('',#477,3.288064662950E-1);
+#479=CARTESIAN_POINT('',(4.671241606803E0,5.471869343405E-1,4.903742888818E0));
+#480=LINE('',#479,#478);
+#481=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#482=PRESENTATION_STYLE_ASSIGNMENT((#481));
+#483=STYLED_ITEM('',(#482),#480);
+#484=DIRECTION('',(1.215183203449E-1,-9.912978866622E-1,5.061420472237E-2));
+#485=VECTOR('',#484,5.519904175151E-1);
+#486=CARTESIAN_POINT('',(4.903742888818E0,5.471869343405E-1,4.671241606803E0));
+#487=LINE('',#486,#485);
+#488=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#489=PRESENTATION_STYLE_ASSIGNMENT((#488));
+#490=STYLED_ITEM('',(#489),#487);
+#491=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#492=VECTOR('',#491,3.841565116167E-1);
+#493=CARTESIAN_POINT('',(4.699180162799E0,1.090840169420E-14,4.970819837201E0));
+#494=LINE('',#493,#492);
+#495=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#496=PRESENTATION_STYLE_ASSIGNMENT((#495));
+#497=STYLED_ITEM('',(#496),#494);
+#498=DIRECTION('',(-5.061420472237E-2,9.912978866622E-1,-1.215183203448E-1));
+#499=VECTOR('',#498,5.519904175151E-1);
+#500=CARTESIAN_POINT('',(4.699180162799E0,1.090840169420E-14,4.970819837201E0));
+#501=LINE('',#500,#499);
+#502=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#503=PRESENTATION_STYLE_ASSIGNMENT((#502));
+#504=STYLED_ITEM('',(#503),#501);
+#505=CARTESIAN_POINT('',(4.601057995356E0,5.35E-1,4.833559277371E0));
+#506=DIRECTION('',(1.E0,0.E0,0.E0));
+#507=DIRECTION('',(0.E0,1.E0,0.E0));
+#508=AXIS2_PLACEMENT_3D('',#505,#506,#507);
+#510=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#511=PRESENTATION_STYLE_ASSIGNMENT((#510));
+#512=STYLED_ITEM('',(#511),#509);
+#513=CARTESIAN_POINT('',(4.601057995356E0,5.35E-1,4.833559277371E0));
+#514=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#515=DIRECTION('',(7.018361144662E-1,1.218693434051E-1,7.018361144662E-1));
+#516=AXIS2_PLACEMENT_3D('',#513,#514,#515);
+#518=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#519=PRESENTATION_STYLE_ASSIGNMENT((#518));
+#520=STYLED_ITEM('',(#519),#517);
+#521=CARTESIAN_POINT('',(4.601057995356E0,5.35E-1,4.833559277371E0));
+#522=DIRECTION('',(-5.041574044985E-2,9.912839485362E-1,-1.217143643511E-1));
+#523=DIRECTION('',(0.E0,1.218693434051E-1,9.925461516413E-1));
+#524=AXIS2_PLACEMENT_3D('',#521,#522,#523);
+#526=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#527=PRESENTATION_STYLE_ASSIGNMENT((#526));
+#528=STYLED_ITEM('',(#527),#525);
+#529=CARTESIAN_POINT('',(4.833559277371E0,5.35E-1,4.601057995356E0));
+#530=DIRECTION('',(-1.217143643511E-1,9.912839485362E-1,-5.041574044985E-2));
+#531=DIRECTION('',(7.018361144662E-1,1.218693434051E-1,7.018361144662E-1));
+#532=AXIS2_PLACEMENT_3D('',#529,#530,#531);
+#534=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#535=PRESENTATION_STYLE_ASSIGNMENT((#534));
+#536=STYLED_ITEM('',(#535),#533);
+#537=CARTESIAN_POINT('',(4.833559277371E0,5.35E-1,4.601057995356E0));
+#538=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#539=DIRECTION('',(0.E0,1.E0,0.E0));
+#540=AXIS2_PLACEMENT_3D('',#537,#538,#539);
+#542=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#543=PRESENTATION_STYLE_ASSIGNMENT((#542));
+#544=STYLED_ITEM('',(#543),#541);
+#545=CARTESIAN_POINT('',(4.833559277371E0,5.35E-1,4.601057995356E0));
+#546=DIRECTION('',(0.E0,0.E0,1.E0));
+#547=DIRECTION('',(9.925461516413E-1,1.218693434051E-1,0.E0));
+#548=AXIS2_PLACEMENT_3D('',#545,#546,#547);
+#550=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#551=PRESENTATION_STYLE_ASSIGNMENT((#550));
+#552=STYLED_ITEM('',(#551),#549);
+#553=CARTESIAN_POINT('',(4.970819837201E0,0.E0,4.699180162799E0));
+#554=CARTESIAN_POINT('',(4.976872408249E0,0.E0,4.693127591751E0));
+#555=CARTESIAN_POINT('',(4.987581634393E0,5.905908534492E-4,4.679186988847E0));
+#556=CARTESIAN_POINT('',(4.997715071581E0,5.905908534550E-4,4.654722707355E0));
+#557=CARTESIAN_POINT('',(5.E0,0.E0,4.637292646081E0));
+#558=CARTESIAN_POINT('',(5.E0,0.E0,4.628733018017E0));
+#560=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#561=PRESENTATION_STYLE_ASSIGNMENT((#560));
+#562=STYLED_ITEM('',(#561),#559);
+#563=DIRECTION('',(-1.217160757378E-1,9.912978866622E-1,5.013678097070E-2));
+#564=VECTOR('',#563,5.519904175151E-1);
+#565=CARTESIAN_POINT('',(5.E0,-2.241573818194E-14,-4.628733018017E0));
+#566=LINE('',#565,#564);
+#567=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#568=PRESENTATION_STYLE_ASSIGNMENT((#567));
+#569=STYLED_ITEM('',(#568),#566);
+#570=DIRECTION('',(0.E0,0.E0,-1.E0));
+#571=VECTOR('',#570,9.257466036034E0);
+#572=CARTESIAN_POINT('',(5.E0,0.E0,4.628733018017E0));
+#573=LINE('',#572,#571);
+#574=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#575=PRESENTATION_STYLE_ASSIGNMENT((#574));
+#576=STYLED_ITEM('',(#575),#573);
+#577=DIRECTION('',(1.217160757378E-1,-9.912978866622E-1,5.013678097069E-2));
+#578=VECTOR('',#577,5.519904175151E-1);
+#579=CARTESIAN_POINT('',(4.932813892535E0,5.471869343405E-1,4.601057995356E0));
+#580=LINE('',#579,#578);
+#581=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#582=PRESENTATION_STYLE_ASSIGNMENT((#581));
+#583=STYLED_ITEM('',(#582),#580);
+#584=DIRECTION('',(0.E0,0.E0,-1.E0));
+#585=VECTOR('',#584,9.202115990712E0);
+#586=CARTESIAN_POINT('',(4.932813892535E0,5.471869343405E-1,4.601057995356E0));
+#587=LINE('',#586,#585);
+#588=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#589=PRESENTATION_STYLE_ASSIGNMENT((#588));
+#590=STYLED_ITEM('',(#589),#587);
+#591=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#592=VECTOR('',#591,3.288064662950E-1);
+#593=CARTESIAN_POINT('',(4.903742888818E0,5.471869343405E-1,-4.671241606803E0));
+#594=LINE('',#593,#592);
+#595=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#596=PRESENTATION_STYLE_ASSIGNMENT((#595));
+#597=STYLED_ITEM('',(#596),#594);
+#598=DIRECTION('',(5.061420472237E-2,-9.912978866622E-1,-1.215183203448E-1));
+#599=VECTOR('',#598,5.519904175151E-1);
+#600=CARTESIAN_POINT('',(4.671241606803E0,5.471869343405E-1,-4.903742888818E0));
+#601=LINE('',#600,#599);
+#602=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#603=PRESENTATION_STYLE_ASSIGNMENT((#602));
+#604=STYLED_ITEM('',(#603),#601);
+#605=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#606=VECTOR('',#605,3.841565116167E-1);
+#607=CARTESIAN_POINT('',(4.970819837201E0,-1.340782942877E-14,
+-4.699180162799E0));
+#608=LINE('',#607,#606);
+#609=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#610=PRESENTATION_STYLE_ASSIGNMENT((#609));
+#611=STYLED_ITEM('',(#610),#608);
+#612=DIRECTION('',(-1.215183203448E-1,9.912978866622E-1,5.061420472237E-2));
+#613=VECTOR('',#612,5.519904175151E-1);
+#614=CARTESIAN_POINT('',(4.970819837201E0,-1.340782942877E-14,
+-4.699180162799E0));
+#615=LINE('',#614,#613);
+#616=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#617=PRESENTATION_STYLE_ASSIGNMENT((#616));
+#618=STYLED_ITEM('',(#617),#615);
+#619=CARTESIAN_POINT('',(4.833559277371E0,5.35E-1,-4.601057995356E0));
+#620=DIRECTION('',(0.E0,0.E0,-1.E0));
+#621=DIRECTION('',(0.E0,1.E0,0.E0));
+#622=AXIS2_PLACEMENT_3D('',#619,#620,#621);
+#624=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#625=PRESENTATION_STYLE_ASSIGNMENT((#624));
+#626=STYLED_ITEM('',(#625),#623);
+#627=CARTESIAN_POINT('',(4.833559277371E0,5.35E-1,-4.601057995356E0));
+#628=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#629=DIRECTION('',(7.018361144662E-1,1.218693434051E-1,-7.018361144662E-1));
+#630=AXIS2_PLACEMENT_3D('',#627,#628,#629);
+#632=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#633=PRESENTATION_STYLE_ASSIGNMENT((#632));
+#634=STYLED_ITEM('',(#633),#631);
+#635=CARTESIAN_POINT('',(4.833559277371E0,5.35E-1,-4.601057995356E0));
+#636=DIRECTION('',(-1.217143643511E-1,9.912839485362E-1,5.041574044985E-2));
+#637=DIRECTION('',(9.925461516413E-1,1.218693434051E-1,0.E0));
+#638=AXIS2_PLACEMENT_3D('',#635,#636,#637);
+#640=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#641=PRESENTATION_STYLE_ASSIGNMENT((#640));
+#642=STYLED_ITEM('',(#641),#639);
+#643=CARTESIAN_POINT('',(4.601057995356E0,5.35E-1,-4.833559277371E0));
+#644=DIRECTION('',(-5.041574044985E-2,9.912839485362E-1,1.217143643511E-1));
+#645=DIRECTION('',(7.018361144662E-1,1.218693434051E-1,-7.018361144662E-1));
+#646=AXIS2_PLACEMENT_3D('',#643,#644,#645);
+#648=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#649=PRESENTATION_STYLE_ASSIGNMENT((#648));
+#650=STYLED_ITEM('',(#649),#647);
+#651=CARTESIAN_POINT('',(4.601057995356E0,5.35E-1,-4.833559277371E0));
+#652=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#653=DIRECTION('',(0.E0,1.E0,0.E0));
+#654=AXIS2_PLACEMENT_3D('',#651,#652,#653);
+#656=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#657=PRESENTATION_STYLE_ASSIGNMENT((#656));
+#658=STYLED_ITEM('',(#657),#655);
+#659=CARTESIAN_POINT('',(4.601057995356E0,5.35E-1,-4.833559277371E0));
+#660=DIRECTION('',(1.E0,0.E0,0.E0));
+#661=DIRECTION('',(0.E0,1.218693434051E-1,-9.925461516413E-1));
+#662=AXIS2_PLACEMENT_3D('',#659,#660,#661);
+#664=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#665=PRESENTATION_STYLE_ASSIGNMENT((#664));
+#666=STYLED_ITEM('',(#665),#663);
+#667=CARTESIAN_POINT('',(4.699180162799E0,-1.149288432330E-14,
+-4.970819837201E0));
+#668=CARTESIAN_POINT('',(4.693127591751E0,-1.061953361829E-14,
+-4.976872408249E0));
+#669=CARTESIAN_POINT('',(4.679186988847E0,5.905908534408E-4,-4.987581634393E0));
+#670=CARTESIAN_POINT('',(4.654722707355E0,5.905908534497E-4,-4.997715071581E0));
+#671=CARTESIAN_POINT('',(4.637292646081E0,0.E0,-5.E0));
+#672=CARTESIAN_POINT('',(4.628733018017E0,0.E0,-5.E0));
+#674=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#675=PRESENTATION_STYLE_ASSIGNMENT((#674));
+#676=STYLED_ITEM('',(#675),#673);
+#677=CARTESIAN_POINT('',(4.699180162799E0,-1.3E-1,-4.970819837201E0));
+#678=CARTESIAN_POINT('',(4.693014394310E0,-1.3E-1,-4.976985605690E0));
+#679=CARTESIAN_POINT('',(4.679246421655E0,-1.305906705500E-1,
+-4.987536217203E0));
+#680=CARTESIAN_POINT('',(4.654648567211E0,-1.305906705500E-1,
+-4.997724982119E0));
+#681=CARTESIAN_POINT('',(4.637452731437E0,-1.3E-1,-5.E0));
+#682=CARTESIAN_POINT('',(4.628733018017E0,-1.3E-1,-5.E0));
+#684=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#685=PRESENTATION_STYLE_ASSIGNMENT((#684));
+#686=STYLED_ITEM('',(#685),#683);
+#687=DIRECTION('',(0.E0,-1.E0,0.E0));
+#688=VECTOR('',#687,1.3E-1);
+#689=CARTESIAN_POINT('',(4.699180162799E0,-1.149288432330E-14,
+-4.970819837201E0));
+#690=LINE('',#689,#688);
+#691=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#692=PRESENTATION_STYLE_ASSIGNMENT((#691));
+#693=STYLED_ITEM('',(#692),#690);
+#694=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#695=VECTOR('',#694,3.841565116167E-1);
+#696=CARTESIAN_POINT('',(4.970819837201E0,-1.3E-1,-4.699180162799E0));
+#697=LINE('',#696,#695);
+#698=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#699=PRESENTATION_STYLE_ASSIGNMENT((#698));
+#700=STYLED_ITEM('',(#699),#697);
+#701=DIRECTION('',(0.E0,-1.E0,0.E0));
+#702=VECTOR('',#701,1.3E-1);
+#703=CARTESIAN_POINT('',(4.970819837201E0,-1.340782942877E-14,
+-4.699180162799E0));
+#704=LINE('',#703,#702);
+#705=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#706=PRESENTATION_STYLE_ASSIGNMENT((#705));
+#707=STYLED_ITEM('',(#706),#704);
+#708=DIRECTION('',(-5.061420472237E-2,-9.912978866622E-1,1.215183203448E-1));
+#709=VECTOR('',#708,5.519904175152E-1);
+#710=CARTESIAN_POINT('',(4.699180162799E0,-1.3E-1,-4.970819837201E0));
+#711=LINE('',#710,#709);
+#712=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#713=PRESENTATION_STYLE_ASSIGNMENT((#712));
+#714=STYLED_ITEM('',(#713),#711);
+#715=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#716=VECTOR('',#715,3.288064662950E-1);
+#717=CARTESIAN_POINT('',(4.671241606803E0,-6.771869343405E-1,
+-4.903742888818E0));
+#718=LINE('',#717,#716);
+#719=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#720=PRESENTATION_STYLE_ASSIGNMENT((#719));
+#721=STYLED_ITEM('',(#720),#718);
+#722=DIRECTION('',(-1.215183203448E-1,-9.912978866622E-1,5.061420472237E-2));
+#723=VECTOR('',#722,5.519904175152E-1);
+#724=CARTESIAN_POINT('',(4.970819837201E0,-1.3E-1,-4.699180162799E0));
+#725=LINE('',#724,#723);
+#726=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#727=PRESENTATION_STYLE_ASSIGNMENT((#726));
+#728=STYLED_ITEM('',(#727),#725);
+#729=DIRECTION('',(1.E0,0.E0,0.E0));
+#730=VECTOR('',#729,9.202115990712E0);
+#731=CARTESIAN_POINT('',(-4.601057995356E0,-6.771869343405E-1,
+-4.932813892535E0));
+#732=LINE('',#731,#730);
+#733=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#734=PRESENTATION_STYLE_ASSIGNMENT((#733));
+#735=STYLED_ITEM('',(#734),#732);
+#736=DIRECTION('',(-5.013678097070E-2,-9.912978866622E-1,1.217160757378E-1));
+#737=VECTOR('',#736,5.519904175151E-1);
+#738=CARTESIAN_POINT('',(4.628733018017E0,-1.3E-1,-5.E0));
+#739=LINE('',#738,#737);
+#740=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#741=PRESENTATION_STYLE_ASSIGNMENT((#740));
+#742=STYLED_ITEM('',(#741),#739);
+#743=DIRECTION('',(5.013678097069E-2,-9.912978866622E-1,1.217160757378E-1));
+#744=VECTOR('',#743,5.519904175151E-1);
+#745=CARTESIAN_POINT('',(-4.628733018017E0,-1.3E-1,-5.E0));
+#746=LINE('',#745,#744);
+#747=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#748=PRESENTATION_STYLE_ASSIGNMENT((#747));
+#749=STYLED_ITEM('',(#748),#746);
+#750=CARTESIAN_POINT('',(-4.601057995356E0,-6.65E-1,-4.833559277371E0));
+#751=DIRECTION('',(5.041574044985E-2,-9.912839485362E-1,1.217143643511E-1));
+#752=DIRECTION('',(-7.018361144662E-1,-1.218693434051E-1,-7.018361144662E-1));
+#753=AXIS2_PLACEMENT_3D('',#750,#751,#752);
+#755=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#756=PRESENTATION_STYLE_ASSIGNMENT((#755));
+#757=STYLED_ITEM('',(#756),#754);
+#758=CARTESIAN_POINT('',(-4.601057995356E0,-6.65E-1,-4.833559277371E0));
+#759=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#760=DIRECTION('',(1.776356839400E-14,-1.E0,1.776356839400E-14));
+#761=AXIS2_PLACEMENT_3D('',#758,#759,#760);
+#763=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#764=PRESENTATION_STYLE_ASSIGNMENT((#763));
+#765=STYLED_ITEM('',(#764),#762);
+#766=CARTESIAN_POINT('',(-4.601057995356E0,-6.65E-1,-4.833559277371E0));
+#767=DIRECTION('',(-1.E0,0.E0,0.E0));
+#768=DIRECTION('',(0.E0,-1.218693434051E-1,-9.925461516413E-1));
+#769=AXIS2_PLACEMENT_3D('',#766,#767,#768);
+#771=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#772=PRESENTATION_STYLE_ASSIGNMENT((#771));
+#773=STYLED_ITEM('',(#772),#770);
+#774=CARTESIAN_POINT('',(-4.699180162799E0,-1.3E-1,-4.970819837201E0));
+#775=CARTESIAN_POINT('',(-4.693127591751E0,-1.3E-1,-4.976872408249E0));
+#776=CARTESIAN_POINT('',(-4.679186988847E0,-1.305905908535E-1,
+-4.987581634393E0));
+#777=CARTESIAN_POINT('',(-4.654722707355E0,-1.305905908534E-1,
+-4.997715071581E0));
+#778=CARTESIAN_POINT('',(-4.637292646081E0,-1.3E-1,-5.E0));
+#779=CARTESIAN_POINT('',(-4.628733018017E0,-1.3E-1,-5.E0));
+#781=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#782=PRESENTATION_STYLE_ASSIGNMENT((#781));
+#783=STYLED_ITEM('',(#782),#780);
+#784=CARTESIAN_POINT('',(-4.699180162799E0,0.E0,-4.970819837201E0));
+#785=CARTESIAN_POINT('',(-4.693014394310E0,0.E0,-4.976985605690E0));
+#786=CARTESIAN_POINT('',(-4.679246421655E0,5.906705500026E-4,
+-4.987536217203E0));
+#787=CARTESIAN_POINT('',(-4.654648567211E0,5.906705500095E-4,
+-4.997724982119E0));
+#788=CARTESIAN_POINT('',(-4.637452731437E0,-1.422407349619E-14,-5.E0));
+#789=CARTESIAN_POINT('',(-4.628733018017E0,-1.384388157703E-14,-5.E0));
+#791=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#792=PRESENTATION_STYLE_ASSIGNMENT((#791));
+#793=STYLED_ITEM('',(#792),#790);
+#794=DIRECTION('',(-2.049642507E-14,-1.E0,0.E0));
+#795=VECTOR('',#794,1.3E-1);
+#796=CARTESIAN_POINT('',(4.628733018017E0,0.E0,-5.E0));
+#797=LINE('',#796,#795);
+#798=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#799=PRESENTATION_STYLE_ASSIGNMENT((#798));
+#800=STYLED_ITEM('',(#799),#797);
+#801=DIRECTION('',(-1.366428338E-14,-1.E0,0.E0));
+#802=VECTOR('',#801,1.3E-1);
+#803=CARTESIAN_POINT('',(-4.628733018017E0,-1.384388157703E-14,-5.E0));
+#804=LINE('',#803,#802);
+#805=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#806=PRESENTATION_STYLE_ASSIGNMENT((#805));
+#807=STYLED_ITEM('',(#806),#804);
+#808=DIRECTION('',(-1.E0,0.E0,0.E0));
+#809=VECTOR('',#808,9.257466036034E0);
+#810=CARTESIAN_POINT('',(4.628733018017E0,-1.3E-1,-5.E0));
+#811=LINE('',#810,#809);
+#812=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#813=PRESENTATION_STYLE_ASSIGNMENT((#812));
+#814=STYLED_ITEM('',(#813),#811);
+#815=DIRECTION('',(0.E0,-1.E0,0.E0));
+#816=VECTOR('',#815,1.3E-1);
+#817=CARTESIAN_POINT('',(-4.970819837201E0,0.E0,-4.699180162799E0));
+#818=LINE('',#817,#816);
+#819=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#820=PRESENTATION_STYLE_ASSIGNMENT((#819));
+#821=STYLED_ITEM('',(#820),#818);
+#822=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#823=VECTOR('',#822,3.841565116167E-1);
+#824=CARTESIAN_POINT('',(-4.699180162799E0,-1.3E-1,-4.970819837201E0));
+#825=LINE('',#824,#823);
+#826=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#827=PRESENTATION_STYLE_ASSIGNMENT((#826));
+#828=STYLED_ITEM('',(#827),#825);
+#829=DIRECTION('',(-1.366428338E-14,-1.E0,0.E0));
+#830=VECTOR('',#829,1.3E-1);
+#831=CARTESIAN_POINT('',(-4.699180162799E0,0.E0,-4.970819837201E0));
+#832=LINE('',#831,#830);
+#833=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#834=PRESENTATION_STYLE_ASSIGNMENT((#833));
+#835=STYLED_ITEM('',(#834),#832);
+#836=CARTESIAN_POINT('',(-5.E0,-1.3E-1,-4.628733018017E0));
+#837=CARTESIAN_POINT('',(-5.E0,-1.3E-1,-4.637292646081E0));
+#838=CARTESIAN_POINT('',(-4.997715071581E0,-1.305905908535E-1,
+-4.654722707355E0));
+#839=CARTESIAN_POINT('',(-4.987581634393E0,-1.305905908535E-1,
+-4.679186988847E0));
+#840=CARTESIAN_POINT('',(-4.976872408249E0,-1.3E-1,-4.693127591751E0));
+#841=CARTESIAN_POINT('',(-4.970819837201E0,-1.3E-1,-4.699180162799E0));
+#843=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#844=PRESENTATION_STYLE_ASSIGNMENT((#843));
+#845=STYLED_ITEM('',(#844),#842);
+#846=DIRECTION('',(1.215183203448E-1,-9.912978866622E-1,5.061420472237E-2));
+#847=VECTOR('',#846,5.519904175151E-1);
+#848=CARTESIAN_POINT('',(-4.970819837201E0,-1.3E-1,-4.699180162799E0));
+#849=LINE('',#848,#847);
+#850=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#851=PRESENTATION_STYLE_ASSIGNMENT((#850));
+#852=STYLED_ITEM('',(#851),#849);
+#853=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811866E-1));
+#854=VECTOR('',#853,3.288064662950E-1);
+#855=CARTESIAN_POINT('',(-4.903742888818E0,-6.771869343405E-1,
+-4.671241606803E0));
+#856=LINE('',#855,#854);
+#857=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#858=PRESENTATION_STYLE_ASSIGNMENT((#857));
+#859=STYLED_ITEM('',(#858),#856);
+#860=DIRECTION('',(5.061420472236E-2,-9.912978866622E-1,1.215183203448E-1));
+#861=VECTOR('',#860,5.519904175151E-1);
+#862=CARTESIAN_POINT('',(-4.699180162799E0,-1.3E-1,-4.970819837201E0));
+#863=LINE('',#862,#861);
+#864=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#865=PRESENTATION_STYLE_ASSIGNMENT((#864));
+#866=STYLED_ITEM('',(#865),#863);
+#867=CARTESIAN_POINT('',(-4.833559277371E0,-6.65E-1,-4.601057995356E0));
+#868=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#869=DIRECTION('',(-7.018361144662E-1,-1.218693434052E-1,-7.018361144662E-1));
+#870=AXIS2_PLACEMENT_3D('',#867,#868,#869);
+#872=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#873=PRESENTATION_STYLE_ASSIGNMENT((#872));
+#874=STYLED_ITEM('',(#873),#871);
+#875=CARTESIAN_POINT('',(-4.833559277371E0,-6.65E-1,-4.601057995356E0));
+#876=DIRECTION('',(1.217143643511E-1,-9.912839485362E-1,5.041574044985E-2));
+#877=DIRECTION('',(-9.925461516413E-1,-1.218693434051E-1,-1.776356839400E-14));
+#878=AXIS2_PLACEMENT_3D('',#875,#876,#877);
+#880=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#881=PRESENTATION_STYLE_ASSIGNMENT((#880));
+#882=STYLED_ITEM('',(#881),#879);
+#883=CARTESIAN_POINT('',(-4.833559277371E0,-6.65E-1,-4.601057995356E0));
+#884=DIRECTION('',(0.E0,0.E0,-1.E0));
+#885=DIRECTION('',(0.E0,-1.E0,0.E0));
+#886=AXIS2_PLACEMENT_3D('',#883,#884,#885);
+#888=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#889=PRESENTATION_STYLE_ASSIGNMENT((#888));
+#890=STYLED_ITEM('',(#889),#887);
+#891=CARTESIAN_POINT('',(-4.833559277371E0,-6.65E-1,4.601057995356E0));
+#892=DIRECTION('',(0.E0,0.E0,1.E0));
+#893=DIRECTION('',(-9.925461516413E-1,-1.218693434051E-1,0.E0));
+#894=AXIS2_PLACEMENT_3D('',#891,#892,#893);
+#896=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#897=PRESENTATION_STYLE_ASSIGNMENT((#896));
+#898=STYLED_ITEM('',(#897),#895);
+#899=CARTESIAN_POINT('',(-4.833559277371E0,-6.65E-1,4.601057995356E0));
+#900=DIRECTION('',(1.217143643511E-1,-9.912839485362E-1,-5.041574044985E-2));
+#901=DIRECTION('',(-7.018361144662E-1,-1.218693434051E-1,7.018361144662E-1));
+#902=AXIS2_PLACEMENT_3D('',#899,#900,#901);
+#904=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#905=PRESENTATION_STYLE_ASSIGNMENT((#904));
+#906=STYLED_ITEM('',(#905),#903);
+#907=CARTESIAN_POINT('',(-4.833559277371E0,-6.65E-1,4.601057995356E0));
+#908=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#909=DIRECTION('',(1.776356839400E-14,-1.E0,-1.776356839400E-14));
+#910=AXIS2_PLACEMENT_3D('',#907,#908,#909);
+#912=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#913=PRESENTATION_STYLE_ASSIGNMENT((#912));
+#914=STYLED_ITEM('',(#913),#911);
+#915=DIRECTION('',(-1.E0,0.E0,0.E0));
+#916=VECTOR('',#915,9.202115990712E0);
+#917=CARTESIAN_POINT('',(4.601057995356E0,-7.65E-1,4.833559277371E0));
+#918=LINE('',#917,#916);
+#919=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#920=PRESENTATION_STYLE_ASSIGNMENT((#919));
+#921=STYLED_ITEM('',(#920),#918);
+#922=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811866E-1));
+#923=VECTOR('',#922,3.288064662950E-1);
+#924=CARTESIAN_POINT('',(4.833559277371E0,-7.65E-1,4.601057995356E0));
+#925=LINE('',#924,#923);
+#926=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#927=PRESENTATION_STYLE_ASSIGNMENT((#926));
+#928=STYLED_ITEM('',(#927),#925);
+#929=DIRECTION('',(0.E0,0.E0,1.E0));
+#930=VECTOR('',#929,9.202115990712E0);
+#931=CARTESIAN_POINT('',(4.833559277371E0,-7.65E-1,-4.601057995356E0));
+#932=LINE('',#931,#930);
+#933=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#934=PRESENTATION_STYLE_ASSIGNMENT((#933));
+#935=STYLED_ITEM('',(#934),#932);
+#936=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#937=VECTOR('',#936,3.288064662950E-1);
+#938=CARTESIAN_POINT('',(4.601057995356E0,-7.65E-1,-4.833559277371E0));
+#939=LINE('',#938,#937);
+#940=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#941=PRESENTATION_STYLE_ASSIGNMENT((#940));
+#942=STYLED_ITEM('',(#941),#939);
+#943=DIRECTION('',(1.E0,0.E0,0.E0));
+#944=VECTOR('',#943,9.202115990712E0);
+#945=CARTESIAN_POINT('',(-4.601057995356E0,-7.65E-1,-4.833559277371E0));
+#946=LINE('',#945,#944);
+#947=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#948=PRESENTATION_STYLE_ASSIGNMENT((#947));
+#949=STYLED_ITEM('',(#948),#946);
+#950=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#951=VECTOR('',#950,3.288064662950E-1);
+#952=CARTESIAN_POINT('',(-4.833559277371E0,-7.65E-1,-4.601057995356E0));
+#953=LINE('',#952,#951);
+#954=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#955=PRESENTATION_STYLE_ASSIGNMENT((#954));
+#956=STYLED_ITEM('',(#955),#953);
+#957=DIRECTION('',(0.E0,0.E0,-1.E0));
+#958=VECTOR('',#957,9.202115990712E0);
+#959=CARTESIAN_POINT('',(-4.833559277371E0,-7.65E-1,4.601057995356E0));
+#960=LINE('',#959,#958);
+#961=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#962=PRESENTATION_STYLE_ASSIGNMENT((#961));
+#963=STYLED_ITEM('',(#962),#960);
+#964=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#965=VECTOR('',#964,3.288064662949E-1);
+#966=CARTESIAN_POINT('',(-4.601057995356E0,-7.65E-1,4.833559277371E0));
+#967=LINE('',#966,#965);
+#968=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#969=PRESENTATION_STYLE_ASSIGNMENT((#968));
+#970=STYLED_ITEM('',(#969),#967);
+#971=DIRECTION('',(-1.E0,0.E0,0.E0));
+#972=VECTOR('',#971,9.202115990712E0);
+#973=CARTESIAN_POINT('',(4.601057995356E0,-6.771869343405E-1,4.932813892535E0));
+#974=LINE('',#973,#972);
+#975=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#976=PRESENTATION_STYLE_ASSIGNMENT((#975));
+#977=STYLED_ITEM('',(#976),#974);
+#978=DIRECTION('',(5.013678097069E-2,-9.912978866622E-1,-1.217160757378E-1));
+#979=VECTOR('',#978,5.519904175151E-1);
+#980=CARTESIAN_POINT('',(-4.628733018017E0,-1.3E-1,5.E0));
+#981=LINE('',#980,#979);
+#982=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#983=PRESENTATION_STYLE_ASSIGNMENT((#982));
+#984=STYLED_ITEM('',(#983),#981);
+#985=DIRECTION('',(-5.013678097070E-2,-9.912978866622E-1,-1.217160757378E-1));
+#986=VECTOR('',#985,5.519904175151E-1);
+#987=CARTESIAN_POINT('',(4.628733018017E0,-1.3E-1,5.E0));
+#988=LINE('',#987,#986);
+#989=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#990=PRESENTATION_STYLE_ASSIGNMENT((#989));
+#991=STYLED_ITEM('',(#990),#988);
+#992=CARTESIAN_POINT('',(-4.601057995356E0,-6.65E-1,4.833559277371E0));
+#993=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#994=DIRECTION('',(-7.018361144662E-1,-1.218693434051E-1,7.018361144662E-1));
+#995=AXIS2_PLACEMENT_3D('',#992,#993,#994);
+#997=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#998=PRESENTATION_STYLE_ASSIGNMENT((#997));
+#999=STYLED_ITEM('',(#998),#996);
+#1000=CARTESIAN_POINT('',(-4.601057995356E0,-6.65E-1,4.833559277371E0));
+#1001=DIRECTION('',(5.041574044985E-2,-9.912839485362E-1,-1.217143643511E-1));
+#1002=DIRECTION('',(-1.776356839400E-14,-1.218693434051E-1,9.925461516413E-1));
+#1003=AXIS2_PLACEMENT_3D('',#1000,#1001,#1002);
+#1005=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1006=PRESENTATION_STYLE_ASSIGNMENT((#1005));
+#1007=STYLED_ITEM('',(#1006),#1004);
+#1008=CARTESIAN_POINT('',(-4.601057995356E0,-6.65E-1,4.833559277371E0));
+#1009=DIRECTION('',(-1.E0,0.E0,0.E0));
+#1010=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1011=AXIS2_PLACEMENT_3D('',#1008,#1009,#1010);
+#1013=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1014=PRESENTATION_STYLE_ASSIGNMENT((#1013));
+#1015=STYLED_ITEM('',(#1014),#1012);
+#1016=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1017=VECTOR('',#1016,1.3E-1);
+#1018=CARTESIAN_POINT('',(4.628733018017E0,1.394331102654E-14,5.E0));
+#1019=LINE('',#1018,#1017);
+#1020=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1021=PRESENTATION_STYLE_ASSIGNMENT((#1020));
+#1022=STYLED_ITEM('',(#1021),#1019);
+#1023=DIRECTION('',(1.E0,0.E0,0.E0));
+#1024=VECTOR('',#1023,9.257466036034E0);
+#1025=CARTESIAN_POINT('',(-4.628733018017E0,-1.3E-1,5.E0));
+#1026=LINE('',#1025,#1024);
+#1027=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1028=PRESENTATION_STYLE_ASSIGNMENT((#1027));
+#1029=STYLED_ITEM('',(#1028),#1026);
+#1030=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1031=VECTOR('',#1030,1.3E-1);
+#1032=CARTESIAN_POINT('',(-4.628733018017E0,1.407937200784E-14,5.E0));
+#1033=LINE('',#1032,#1031);
+#1034=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1035=PRESENTATION_STYLE_ASSIGNMENT((#1034));
+#1036=STYLED_ITEM('',(#1035),#1033);
+#1037=CARTESIAN_POINT('',(4.699180162799E0,1.090840169420E-14,
+4.970819837201E0));
+#1038=CARTESIAN_POINT('',(4.693014394310E0,1.223498473646E-14,
+4.976985605690E0));
+#1039=CARTESIAN_POINT('',(4.679246421655E0,5.906705500214E-4,4.987536217203E0));
+#1040=CARTESIAN_POINT('',(4.654648567211E0,5.906705500252E-4,4.997724982119E0));
+#1041=CARTESIAN_POINT('',(4.637452731437E0,1.306875909092E-14,5.E0));
+#1042=CARTESIAN_POINT('',(4.628733018017E0,1.394331102654E-14,5.E0));
+#1044=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1045=PRESENTATION_STYLE_ASSIGNMENT((#1044));
+#1046=STYLED_ITEM('',(#1045),#1043);
+#1047=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1048=VECTOR('',#1047,1.3E-1);
+#1049=CARTESIAN_POINT('',(4.970819837201E0,0.E0,4.699180162799E0));
+#1050=LINE('',#1049,#1048);
+#1051=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1052=PRESENTATION_STYLE_ASSIGNMENT((#1051));
+#1053=STYLED_ITEM('',(#1052),#1050);
+#1054=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#1055=VECTOR('',#1054,3.841565116167E-1);
+#1056=CARTESIAN_POINT('',(4.970819837201E0,-1.3E-1,4.699180162799E0));
+#1057=LINE('',#1056,#1055);
+#1058=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1059=PRESENTATION_STYLE_ASSIGNMENT((#1058));
+#1060=STYLED_ITEM('',(#1059),#1057);
+#1061=DIRECTION('',(0.E0,-1.E0,2.049642507E-14));
+#1062=VECTOR('',#1061,1.3E-1);
+#1063=CARTESIAN_POINT('',(4.699180162799E0,1.090840169420E-14,
+4.970819837201E0));
+#1064=LINE('',#1063,#1062);
+#1065=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1066=PRESENTATION_STYLE_ASSIGNMENT((#1065));
+#1067=STYLED_ITEM('',(#1066),#1064);
+#1068=CARTESIAN_POINT('',(4.970819837201E0,-1.3E-1,4.699180162799E0));
+#1069=CARTESIAN_POINT('',(4.976985605690E0,-1.3E-1,4.693014394310E0));
+#1070=CARTESIAN_POINT('',(4.987536217203E0,-1.305906705500E-1,
+4.679246421655E0));
+#1071=CARTESIAN_POINT('',(4.997724982119E0,-1.305906705500E-1,
+4.654648567211E0));
+#1072=CARTESIAN_POINT('',(5.E0,-1.3E-1,4.637452731437E0));
+#1073=CARTESIAN_POINT('',(5.E0,-1.3E-1,4.628733018017E0));
+#1075=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1076=PRESENTATION_STYLE_ASSIGNMENT((#1075));
+#1077=STYLED_ITEM('',(#1076),#1074);
+#1078=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1079=VECTOR('',#1078,1.299999999999E-1);
+#1080=CARTESIAN_POINT('',(5.E0,-2.241573818194E-14,-4.628733018017E0));
+#1081=LINE('',#1080,#1079);
+#1082=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1083=PRESENTATION_STYLE_ASSIGNMENT((#1082));
+#1084=STYLED_ITEM('',(#1083),#1081);
+#1085=DIRECTION('',(0.E0,0.E0,-1.E0));
+#1086=VECTOR('',#1085,9.257466036034E0);
+#1087=CARTESIAN_POINT('',(5.E0,-1.3E-1,4.628733018017E0));
+#1088=LINE('',#1087,#1086);
+#1089=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1090=PRESENTATION_STYLE_ASSIGNMENT((#1089));
+#1091=STYLED_ITEM('',(#1090),#1088);
+#1092=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1093=VECTOR('',#1092,1.3E-1);
+#1094=CARTESIAN_POINT('',(5.E0,0.E0,4.628733018017E0));
+#1095=LINE('',#1094,#1093);
+#1096=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1097=PRESENTATION_STYLE_ASSIGNMENT((#1096));
+#1098=STYLED_ITEM('',(#1097),#1095);
+#1099=CARTESIAN_POINT('',(4.970819837201E0,-1.340782942877E-14,
+-4.699180162799E0));
+#1100=CARTESIAN_POINT('',(4.976985605690E0,-1.474235608207E-14,
+-4.693014394310E0));
+#1101=CARTESIAN_POINT('',(4.987536217203E0,5.906705499908E-4,
+-4.679246421655E0));
+#1102=CARTESIAN_POINT('',(4.997724982119E0,5.906705499917E-4,
+-4.654648567211E0));
+#1103=CARTESIAN_POINT('',(5.E0,-2.341840487550E-14,-4.637452731437E0));
+#1104=CARTESIAN_POINT('',(5.E0,-2.241573818194E-14,-4.628733018017E0));
+#1106=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1107=PRESENTATION_STYLE_ASSIGNMENT((#1106));
+#1108=STYLED_ITEM('',(#1107),#1105);
+#1109=CARTESIAN_POINT('',(4.970819837201E0,-1.3E-1,-4.699180162799E0));
+#1110=CARTESIAN_POINT('',(4.976872408249E0,-1.3E-1,-4.693127591751E0));
+#1111=CARTESIAN_POINT('',(4.987581634393E0,-1.305905908534E-1,
+-4.679186988847E0));
+#1112=CARTESIAN_POINT('',(4.997715071581E0,-1.305905908534E-1,
+-4.654722707355E0));
+#1113=CARTESIAN_POINT('',(5.E0,-1.3E-1,-4.637292646081E0));
+#1114=CARTESIAN_POINT('',(5.E0,-1.3E-1,-4.628733018017E0));
+#1116=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1117=PRESENTATION_STYLE_ASSIGNMENT((#1116));
+#1118=STYLED_ITEM('',(#1117),#1115);
+#1119=DIRECTION('',(0.E0,0.E0,1.E0));
+#1120=VECTOR('',#1119,9.202115990712E0);
+#1121=CARTESIAN_POINT('',(4.932813892535E0,-6.771869343405E-1,
+-4.601057995356E0));
+#1122=LINE('',#1121,#1120);
+#1123=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1124=PRESENTATION_STYLE_ASSIGNMENT((#1123));
+#1125=STYLED_ITEM('',(#1124),#1122);
+#1126=DIRECTION('',(-1.217160757378E-1,-9.912978866622E-1,-5.013678097069E-2));
+#1127=VECTOR('',#1126,5.519904175152E-1);
+#1128=CARTESIAN_POINT('',(5.E0,-1.3E-1,4.628733018017E0));
+#1129=LINE('',#1128,#1127);
+#1130=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1131=PRESENTATION_STYLE_ASSIGNMENT((#1130));
+#1132=STYLED_ITEM('',(#1131),#1129);
+#1133=DIRECTION('',(-1.217160757378E-1,-9.912978866622E-1,5.013678097069E-2));
+#1134=VECTOR('',#1133,5.519904175152E-1);
+#1135=CARTESIAN_POINT('',(5.E0,-1.3E-1,-4.628733018017E0));
+#1136=LINE('',#1135,#1134);
+#1137=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1138=PRESENTATION_STYLE_ASSIGNMENT((#1137));
+#1139=STYLED_ITEM('',(#1138),#1136);
+#1140=CARTESIAN_POINT('',(4.833559277371E0,-6.65E-1,-4.601057995356E0));
+#1141=DIRECTION('',(-1.217143643511E-1,-9.912839485362E-1,5.041574044985E-2));
+#1142=DIRECTION('',(7.018361144662E-1,-1.218693434051E-1,-7.018361144662E-1));
+#1143=AXIS2_PLACEMENT_3D('',#1140,#1141,#1142);
+#1145=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1146=PRESENTATION_STYLE_ASSIGNMENT((#1145));
+#1147=STYLED_ITEM('',(#1146),#1144);
+#1148=CARTESIAN_POINT('',(4.833559277371E0,-6.65E-1,-4.601057995356E0));
+#1149=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#1150=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1151=AXIS2_PLACEMENT_3D('',#1148,#1149,#1150);
+#1153=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1154=PRESENTATION_STYLE_ASSIGNMENT((#1153));
+#1155=STYLED_ITEM('',(#1154),#1152);
+#1156=CARTESIAN_POINT('',(4.833559277371E0,-6.65E-1,-4.601057995356E0));
+#1157=DIRECTION('',(0.E0,0.E0,-1.E0));
+#1158=DIRECTION('',(9.925461516413E-1,-1.218693434051E-1,0.E0));
+#1159=AXIS2_PLACEMENT_3D('',#1156,#1157,#1158);
+#1161=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1162=PRESENTATION_STYLE_ASSIGNMENT((#1161));
+#1163=STYLED_ITEM('',(#1162),#1160);
+#1164=CARTESIAN_POINT('',(4.601057995356E0,-6.65E-1,-4.833559277371E0));
+#1165=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#1166=DIRECTION('',(7.018361144662E-1,-1.218693434051E-1,-7.018361144662E-1));
+#1167=AXIS2_PLACEMENT_3D('',#1164,#1165,#1166);
+#1169=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1170=PRESENTATION_STYLE_ASSIGNMENT((#1169));
+#1171=STYLED_ITEM('',(#1170),#1168);
+#1172=CARTESIAN_POINT('',(4.601057995356E0,-6.65E-1,-4.833559277371E0));
+#1173=DIRECTION('',(-5.041574044985E-2,-9.912839485362E-1,1.217143643511E-1));
+#1174=DIRECTION('',(1.776356839400E-14,-1.218693434051E-1,-9.925461516413E-1));
+#1175=AXIS2_PLACEMENT_3D('',#1172,#1173,#1174);
+#1177=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1178=PRESENTATION_STYLE_ASSIGNMENT((#1177));
+#1179=STYLED_ITEM('',(#1178),#1176);
+#1180=CARTESIAN_POINT('',(4.601057995356E0,-6.65E-1,-4.833559277371E0));
+#1181=DIRECTION('',(1.E0,0.E0,0.E0));
+#1182=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1183=AXIS2_PLACEMENT_3D('',#1180,#1181,#1182);
+#1185=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1186=PRESENTATION_STYLE_ASSIGNMENT((#1185));
+#1187=STYLED_ITEM('',(#1186),#1184);
+#1188=CARTESIAN_POINT('',(4.833559277371E0,-6.65E-1,4.601057995356E0));
+#1189=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#1190=DIRECTION('',(7.018361144662E-1,-1.218693434051E-1,7.018361144662E-1));
+#1191=AXIS2_PLACEMENT_3D('',#1188,#1189,#1190);
+#1193=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1194=PRESENTATION_STYLE_ASSIGNMENT((#1193));
+#1195=STYLED_ITEM('',(#1194),#1192);
+#1196=CARTESIAN_POINT('',(4.833559277371E0,-6.65E-1,4.601057995356E0));
+#1197=DIRECTION('',(-1.217143643511E-1,-9.912839485362E-1,-5.041574044985E-2));
+#1198=DIRECTION('',(9.925461516413E-1,-1.218693434051E-1,0.E0));
+#1199=AXIS2_PLACEMENT_3D('',#1196,#1197,#1198);
+#1201=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1202=PRESENTATION_STYLE_ASSIGNMENT((#1201));
+#1203=STYLED_ITEM('',(#1202),#1200);
+#1204=CARTESIAN_POINT('',(4.833559277371E0,-6.65E-1,4.601057995356E0));
+#1205=DIRECTION('',(0.E0,0.E0,1.E0));
+#1206=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1207=AXIS2_PLACEMENT_3D('',#1204,#1205,#1206);
+#1209=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1210=PRESENTATION_STYLE_ASSIGNMENT((#1209));
+#1211=STYLED_ITEM('',(#1210),#1208);
+#1212=CARTESIAN_POINT('',(4.601057995356E0,-6.65E-1,4.833559277371E0));
+#1213=DIRECTION('',(-5.041574044985E-2,-9.912839485362E-1,-1.217143643511E-1));
+#1214=DIRECTION('',(7.018361144662E-1,-1.218693434051E-1,7.018361144662E-1));
+#1215=AXIS2_PLACEMENT_3D('',#1212,#1213,#1214);
+#1217=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1218=PRESENTATION_STYLE_ASSIGNMENT((#1217));
+#1219=STYLED_ITEM('',(#1218),#1216);
+#1220=CARTESIAN_POINT('',(4.601057995356E0,-6.65E-1,4.833559277371E0));
+#1221=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#1222=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1223=AXIS2_PLACEMENT_3D('',#1220,#1221,#1222);
+#1225=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1226=PRESENTATION_STYLE_ASSIGNMENT((#1225));
+#1227=STYLED_ITEM('',(#1226),#1224);
+#1228=CARTESIAN_POINT('',(4.601057995356E0,-6.65E-1,4.833559277371E0));
+#1229=DIRECTION('',(1.E0,0.E0,0.E0));
+#1230=DIRECTION('',(0.E0,-1.218693434051E-1,9.925461516413E-1));
+#1231=AXIS2_PLACEMENT_3D('',#1228,#1229,#1230);
+#1233=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1234=PRESENTATION_STYLE_ASSIGNMENT((#1233));
+#1235=STYLED_ITEM('',(#1234),#1232);
+#1236=CARTESIAN_POINT('',(4.699180162799E0,-1.3E-1,4.970819837201E0));
+#1237=CARTESIAN_POINT('',(4.693127591751E0,-1.3E-1,4.976872408249E0));
+#1238=CARTESIAN_POINT('',(4.679186988847E0,-1.305905908534E-1,
+4.987581634393E0));
+#1239=CARTESIAN_POINT('',(4.654722707355E0,-1.305905908535E-1,
+4.997715071581E0));
+#1240=CARTESIAN_POINT('',(4.637292646081E0,-1.3E-1,5.E0));
+#1241=CARTESIAN_POINT('',(4.628733018017E0,-1.3E-1,5.E0));
+#1243=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1244=PRESENTATION_STYLE_ASSIGNMENT((#1243));
+#1245=STYLED_ITEM('',(#1244),#1242);
+#1246=DIRECTION('',(-1.215183203449E-1,-9.912978866622E-1,-5.061420472237E-2));
+#1247=VECTOR('',#1246,5.519904175151E-1);
+#1248=CARTESIAN_POINT('',(4.970819837201E0,-1.3E-1,4.699180162799E0));
+#1249=LINE('',#1248,#1247);
+#1250=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1251=PRESENTATION_STYLE_ASSIGNMENT((#1250));
+#1252=STYLED_ITEM('',(#1251),#1249);
+#1253=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#1254=VECTOR('',#1253,3.288064662950E-1);
+#1255=CARTESIAN_POINT('',(4.903742888818E0,-6.771869343405E-1,
+4.671241606803E0));
+#1256=LINE('',#1255,#1254);
+#1257=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1258=PRESENTATION_STYLE_ASSIGNMENT((#1257));
+#1259=STYLED_ITEM('',(#1258),#1256);
+#1260=DIRECTION('',(-5.061420472237E-2,-9.912978866622E-1,-1.215183203449E-1));
+#1261=VECTOR('',#1260,5.519904175151E-1);
+#1262=CARTESIAN_POINT('',(4.699180162799E0,-1.3E-1,4.970819837201E0));
+#1263=LINE('',#1262,#1261);
+#1264=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1265=PRESENTATION_STYLE_ASSIGNMENT((#1264));
+#1266=STYLED_ITEM('',(#1265),#1263);
+#1267=CARTESIAN_POINT('',(-4.601057995356E0,5.35E-1,-4.833559277371E0));
+#1268=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#1269=DIRECTION('',(-7.018361144662E-1,1.218693434051E-1,-7.018361144662E-1));
+#1270=AXIS2_PLACEMENT_3D('',#1267,#1268,#1269);
+#1272=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1273=PRESENTATION_STYLE_ASSIGNMENT((#1272));
+#1274=STYLED_ITEM('',(#1273),#1271);
+#1275=CARTESIAN_POINT('',(-4.601057995356E0,5.35E-1,-4.833559277371E0));
+#1276=DIRECTION('',(5.041574044985E-2,9.912839485362E-1,1.217143643511E-1));
+#1277=DIRECTION('',(0.E0,1.218693434051E-1,-9.925461516413E-1));
+#1278=AXIS2_PLACEMENT_3D('',#1275,#1276,#1277);
+#1280=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1281=PRESENTATION_STYLE_ASSIGNMENT((#1280));
+#1282=STYLED_ITEM('',(#1281),#1279);
+#1283=CARTESIAN_POINT('',(-4.601057995356E0,5.35E-1,-4.833559277371E0));
+#1284=DIRECTION('',(-1.E0,0.E0,0.E0));
+#1285=DIRECTION('',(0.E0,1.E0,0.E0));
+#1286=AXIS2_PLACEMENT_3D('',#1283,#1284,#1285);
+#1288=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#6);
+#1289=PRESENTATION_STYLE_ASSIGNMENT((#1288));
+#1290=STYLED_ITEM('',(#1289),#1287);
+#1291=CARTESIAN_POINT('',(-4.05E0,5.85E-1,-4.3E0));
+#1292=CARTESIAN_POINT('',(-4.55E0,5.85E-1,-4.3E0));
+#1293=VERTEX_POINT('',#1291);
+#1294=VERTEX_POINT('',#1292);
+#1295=CARTESIAN_POINT('',(-4.05E0,6.35E-1,-4.3E0));
+#1296=CARTESIAN_POINT('',(-4.55E0,6.35E-1,-4.3E0));
+#1297=VERTEX_POINT('',#1295);
+#1298=VERTEX_POINT('',#1296);
+#1299=CARTESIAN_POINT('',(4.601057995356E0,-6.771869343405E-1,
+4.932813892535E0));
+#1300=CARTESIAN_POINT('',(-4.601057995356E0,-6.771869343405E-1,
+4.932813892535E0));
+#1301=VERTEX_POINT('',#1299);
+#1302=VERTEX_POINT('',#1300);
+#1303=CARTESIAN_POINT('',(4.601057995356E0,-7.65E-1,4.833559277371E0));
+#1304=CARTESIAN_POINT('',(-4.601057995356E0,-7.65E-1,4.833559277371E0));
+#1305=VERTEX_POINT('',#1303);
+#1306=VERTEX_POINT('',#1304);
+#1307=CARTESIAN_POINT('',(4.932813892535E0,-6.771869343405E-1,
+-4.601057995356E0));
+#1308=CARTESIAN_POINT('',(4.932813892535E0,-6.771869343405E-1,
+4.601057995356E0));
+#1309=VERTEX_POINT('',#1307);
+#1310=VERTEX_POINT('',#1308);
+#1311=CARTESIAN_POINT('',(4.833559277371E0,-7.65E-1,-4.601057995356E0));
+#1312=CARTESIAN_POINT('',(4.833559277371E0,-7.65E-1,4.601057995356E0));
+#1313=VERTEX_POINT('',#1311);
+#1314=VERTEX_POINT('',#1312);
+#1315=CARTESIAN_POINT('',(-4.601057995356E0,-6.771869343405E-1,
+-4.932813892535E0));
+#1316=CARTESIAN_POINT('',(4.601057995356E0,-6.771869343405E-1,
+-4.932813892535E0));
+#1317=VERTEX_POINT('',#1315);
+#1318=VERTEX_POINT('',#1316);
+#1319=CARTESIAN_POINT('',(-4.601057995356E0,-7.65E-1,-4.833559277371E0));
+#1320=CARTESIAN_POINT('',(4.601057995356E0,-7.65E-1,-4.833559277371E0));
+#1321=VERTEX_POINT('',#1319);
+#1322=VERTEX_POINT('',#1320);
+#1323=CARTESIAN_POINT('',(4.601057995356E0,5.471869343405E-1,
+-4.932813892535E0));
+#1324=CARTESIAN_POINT('',(-4.601057995356E0,5.471869343405E-1,
+-4.932813892535E0));
+#1325=VERTEX_POINT('',#1323);
+#1326=VERTEX_POINT('',#1324);
+#1327=CARTESIAN_POINT('',(4.601057995356E0,6.35E-1,-4.833559277371E0));
+#1328=CARTESIAN_POINT('',(-4.601057995356E0,6.35E-1,-4.833559277371E0));
+#1329=VERTEX_POINT('',#1327);
+#1330=VERTEX_POINT('',#1328);
+#1331=CARTESIAN_POINT('',(4.903742888818E0,5.471869343405E-1,
+-4.671241606803E0));
+#1332=CARTESIAN_POINT('',(4.671241606803E0,5.471869343405E-1,
+-4.903742888818E0));
+#1333=VERTEX_POINT('',#1331);
+#1334=VERTEX_POINT('',#1332);
+#1335=CARTESIAN_POINT('',(4.833559277371E0,6.35E-1,-4.601057995356E0));
+#1336=VERTEX_POINT('',#1335);
+#1337=CARTESIAN_POINT('',(4.699180162799E0,-1.154631945610E-14,
+-4.970819837201E0));
+#1338=VERTEX_POINT('',#1337);
+#1339=CARTESIAN_POINT('',(4.628733018017E0,0.E0,-5.E0));
+#1340=VERTEX_POINT('',#1339);
+#1341=CARTESIAN_POINT('',(4.699180162799E0,-1.3E-1,-4.970819837201E0));
+#1342=VERTEX_POINT('',#1341);
+#1343=CARTESIAN_POINT('',(4.628733018017E0,-1.3E-1,-5.E0));
+#1344=VERTEX_POINT('',#1343);
+#1345=CARTESIAN_POINT('',(4.671241606803E0,-6.771869343405E-1,
+-4.903742888818E0));
+#1346=VERTEX_POINT('',#1345);
+#1347=CARTESIAN_POINT('',(4.903742888818E0,-6.771869343405E-1,
+-4.671241606803E0));
+#1348=VERTEX_POINT('',#1347);
+#1349=CARTESIAN_POINT('',(5.E0,-1.3E-1,-4.628733018017E0));
+#1350=VERTEX_POINT('',#1349);
+#1351=CARTESIAN_POINT('',(4.970819837201E0,-1.3E-1,-4.699180162799E0));
+#1352=VERTEX_POINT('',#1351);
+#1353=CARTESIAN_POINT('',(5.E0,-2.241573818194E-14,-4.628733018017E0));
+#1354=VERTEX_POINT('',#1353);
+#1355=CARTESIAN_POINT('',(4.970819837201E0,-1.340782942877E-14,
+-4.699180162799E0));
+#1356=VERTEX_POINT('',#1355);
+#1357=CARTESIAN_POINT('',(4.932813892535E0,5.471869343405E-1,
+-4.601057995356E0));
+#1358=VERTEX_POINT('',#1357);
+#1359=CARTESIAN_POINT('',(4.932813892535E0,5.471869343405E-1,4.601057995356E0));
+#1360=VERTEX_POINT('',#1359);
+#1361=CARTESIAN_POINT('',(4.833559277371E0,6.35E-1,4.601057995356E0));
+#1362=VERTEX_POINT('',#1361);
+#1363=CARTESIAN_POINT('',(4.671241606803E0,5.471869343405E-1,4.903742888818E0));
+#1364=CARTESIAN_POINT('',(4.903742888818E0,5.471869343405E-1,4.671241606803E0));
+#1365=VERTEX_POINT('',#1363);
+#1366=VERTEX_POINT('',#1364);
+#1367=CARTESIAN_POINT('',(4.601057995356E0,6.35E-1,4.833559277371E0));
+#1368=VERTEX_POINT('',#1367);
+#1369=CARTESIAN_POINT('',(4.970819837201E0,0.E0,4.699180162799E0));
+#1370=VERTEX_POINT('',#1369);
+#1371=CARTESIAN_POINT('',(5.E0,0.E0,4.628733018017E0));
+#1372=VERTEX_POINT('',#1371);
+#1373=CARTESIAN_POINT('',(4.970819837201E0,-1.3E-1,4.699180162799E0));
+#1374=VERTEX_POINT('',#1373);
+#1375=CARTESIAN_POINT('',(5.E0,-1.3E-1,4.628733018017E0));
+#1376=VERTEX_POINT('',#1375);
+#1377=CARTESIAN_POINT('',(4.903742888818E0,-6.771869343405E-1,
+4.671241606803E0));
+#1378=VERTEX_POINT('',#1377);
+#1379=CARTESIAN_POINT('',(4.671241606803E0,-6.771869343405E-1,
+4.903742888818E0));
+#1380=VERTEX_POINT('',#1379);
+#1381=CARTESIAN_POINT('',(4.628733018017E0,-1.3E-1,5.E0));
+#1382=VERTEX_POINT('',#1381);
+#1383=CARTESIAN_POINT('',(4.699180162799E0,-1.3E-1,4.970819837201E0));
+#1384=VERTEX_POINT('',#1383);
+#1385=CARTESIAN_POINT('',(4.628733018017E0,1.394331102654E-14,5.E0));
+#1386=VERTEX_POINT('',#1385);
+#1387=CARTESIAN_POINT('',(4.699180162799E0,1.090840169420E-14,
+4.970819837201E0));
+#1388=VERTEX_POINT('',#1387);
+#1389=CARTESIAN_POINT('',(4.601057995356E0,5.471869343405E-1,4.932813892535E0));
+#1390=VERTEX_POINT('',#1389);
+#1391=CARTESIAN_POINT('',(-4.601057995356E0,5.471869343405E-1,
+4.932813892535E0));
+#1392=VERTEX_POINT('',#1391);
+#1393=CARTESIAN_POINT('',(-4.601057995356E0,6.35E-1,4.833559277371E0));
+#1394=VERTEX_POINT('',#1393);
+#1395=CARTESIAN_POINT('',(-4.932813892535E0,5.471869343405E-1,
+-4.601057995356E0));
+#1396=CARTESIAN_POINT('',(-4.932813892535E0,5.471869343405E-1,
+4.601057995356E0));
+#1397=VERTEX_POINT('',#1395);
+#1398=VERTEX_POINT('',#1396);
+#1399=CARTESIAN_POINT('',(-4.833559277371E0,6.35E-1,-4.601057995356E0));
+#1400=CARTESIAN_POINT('',(-4.833559277371E0,6.35E-1,4.601057995356E0));
+#1401=VERTEX_POINT('',#1399);
+#1402=VERTEX_POINT('',#1400);
+#1403=CARTESIAN_POINT('',(-5.E0,-1.3E-1,4.628733018017E0));
+#1404=CARTESIAN_POINT('',(-4.932813892535E0,-6.771869343405E-1,
+4.601057995356E0));
+#1405=VERTEX_POINT('',#1403);
+#1406=VERTEX_POINT('',#1404);
+#1407=CARTESIAN_POINT('',(-4.970819837201E0,-1.3E-1,4.699180162799E0));
+#1408=CARTESIAN_POINT('',(-4.903742888818E0,-6.771869343405E-1,
+4.671241606803E0));
+#1409=VERTEX_POINT('',#1407);
+#1410=VERTEX_POINT('',#1408);
+#1411=CARTESIAN_POINT('',(-5.E0,0.E0,4.628733018017E0));
+#1412=VERTEX_POINT('',#1411);
+#1413=CARTESIAN_POINT('',(-4.970819837201E0,1.704336290632E-14,
+4.699180162799E0));
+#1414=VERTEX_POINT('',#1413);
+#1415=CARTESIAN_POINT('',(-4.903742888818E0,5.471869343405E-1,
+4.671241606803E0));
+#1416=VERTEX_POINT('',#1415);
+#1417=CARTESIAN_POINT('',(-4.671241606803E0,5.471869343405E-1,
+4.903742888818E0));
+#1418=VERTEX_POINT('',#1417);
+#1419=CARTESIAN_POINT('',(-4.699180162799E0,1.176836406103E-14,
+4.970819837201E0));
+#1420=VERTEX_POINT('',#1419);
+#1421=CARTESIAN_POINT('',(-4.628733018017E0,1.409983241274E-14,5.E0));
+#1422=VERTEX_POINT('',#1421);
+#1423=CARTESIAN_POINT('',(-4.699180162799E0,-1.3E-1,4.970819837201E0));
+#1424=VERTEX_POINT('',#1423);
+#1425=CARTESIAN_POINT('',(-4.628733018017E0,-1.3E-1,5.E0));
+#1426=VERTEX_POINT('',#1425);
+#1427=CARTESIAN_POINT('',(-4.671241606803E0,-6.771869343405E-1,
+4.903742888818E0));
+#1428=VERTEX_POINT('',#1427);
+#1429=CARTESIAN_POINT('',(-4.833559277371E0,-7.65E-1,4.601057995356E0));
+#1430=VERTEX_POINT('',#1429);
+#1431=CARTESIAN_POINT('',(-4.932813892535E0,-6.771869343405E-1,
+-4.601057995356E0));
+#1432=VERTEX_POINT('',#1431);
+#1433=CARTESIAN_POINT('',(-4.833559277371E0,-7.65E-1,-4.601057995356E0));
+#1434=VERTEX_POINT('',#1433);
+#1435=CARTESIAN_POINT('',(-4.970819837201E0,0.E0,-4.699180162799E0));
+#1436=CARTESIAN_POINT('',(-4.970819837201E0,-1.3E-1,-4.699180162799E0));
+#1437=VERTEX_POINT('',#1435);
+#1438=VERTEX_POINT('',#1436);
+#1439=CARTESIAN_POINT('',(-5.E0,0.E0,-4.628733018017E0));
+#1440=CARTESIAN_POINT('',(-5.E0,-1.3E-1,-4.628733018017E0));
+#1441=VERTEX_POINT('',#1439);
+#1442=VERTEX_POINT('',#1440);
+#1443=CARTESIAN_POINT('',(-4.903742888818E0,-6.771869343405E-1,
+-4.671241606803E0));
+#1444=VERTEX_POINT('',#1443);
+#1445=CARTESIAN_POINT('',(-4.671241606803E0,-6.771869343405E-1,
+-4.903742888818E0));
+#1446=VERTEX_POINT('',#1445);
+#1447=CARTESIAN_POINT('',(-4.628733018017E0,-1.3E-1,-5.E0));
+#1448=VERTEX_POINT('',#1447);
+#1449=CARTESIAN_POINT('',(-4.699180162799E0,-1.3E-1,-4.970819837201E0));
+#1450=VERTEX_POINT('',#1449);
+#1451=CARTESIAN_POINT('',(-4.628733018017E0,-1.384388157703E-14,-5.E0));
+#1452=VERTEX_POINT('',#1451);
+#1453=CARTESIAN_POINT('',(-4.699180162799E0,0.E0,-4.970819837201E0));
+#1454=VERTEX_POINT('',#1453);
+#1455=CARTESIAN_POINT('',(-4.671241606803E0,5.471869343405E-1,
+-4.903742888818E0));
+#1456=VERTEX_POINT('',#1455);
+#1457=CARTESIAN_POINT('',(-4.903742888818E0,5.471869343405E-1,
+-4.671241606803E0));
+#1458=VERTEX_POINT('',#1457);
+#1459=CARTESIAN_POINT('',(0.E0,6.35E-1,0.E0));
+#1460=DIRECTION('',(0.E0,1.E0,0.E0));
+#1461=DIRECTION('',(1.E0,0.E0,0.E0));
+#1462=AXIS2_PLACEMENT_3D('',#1459,#1460,#1461);
+#1463=PLANE('',#1462);
+#1465=ORIENTED_EDGE('',*,*,#1464,.F.);
+#1467=ORIENTED_EDGE('',*,*,#1466,.F.);
+#1469=ORIENTED_EDGE('',*,*,#1468,.F.);
+#1471=ORIENTED_EDGE('',*,*,#1470,.F.);
+#1473=ORIENTED_EDGE('',*,*,#1472,.F.);
+#1475=ORIENTED_EDGE('',*,*,#1474,.F.);
+#1477=ORIENTED_EDGE('',*,*,#1476,.F.);
+#1479=ORIENTED_EDGE('',*,*,#1478,.F.);
+#1480=EDGE_LOOP('',(#1465,#1467,#1469,#1471,#1473,#1475,#1477,#1479));
+#1481=FACE_OUTER_BOUND('',#1480,.F.);
+#1483=ORIENTED_EDGE('',*,*,#1482,.F.);
+#1485=ORIENTED_EDGE('',*,*,#1484,.F.);
+#1486=EDGE_LOOP('',(#1483,#1485));
+#1487=FACE_BOUND('',#1486,.F.);
+#1489=CARTESIAN_POINT('',(-4.3E0,6.35E-1,-4.3E0));
+#1490=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1491=DIRECTION('',(1.E0,0.E0,0.E0));
+#1492=AXIS2_PLACEMENT_3D('',#1489,#1490,#1491);
+#1493=CYLINDRICAL_SURFACE('',#1492,2.5E-1);
+#1494=ORIENTED_EDGE('',*,*,#1482,.T.);
+#1496=ORIENTED_EDGE('',*,*,#1495,.T.);
+#1498=ORIENTED_EDGE('',*,*,#1497,.F.);
+#1500=ORIENTED_EDGE('',*,*,#1499,.F.);
+#1501=EDGE_LOOP('',(#1494,#1496,#1498,#1500));
+#1502=FACE_OUTER_BOUND('',#1501,.F.);
+#1504=CARTESIAN_POINT('',(-4.3E0,6.35E-1,-4.3E0));
+#1505=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1506=DIRECTION('',(1.E0,0.E0,0.E0));
+#1507=AXIS2_PLACEMENT_3D('',#1504,#1505,#1506);
+#1508=CYLINDRICAL_SURFACE('',#1507,2.5E-1);
+#1509=ORIENTED_EDGE('',*,*,#1484,.T.);
+#1510=ORIENTED_EDGE('',*,*,#1499,.T.);
+#1512=ORIENTED_EDGE('',*,*,#1511,.F.);
+#1513=ORIENTED_EDGE('',*,*,#1495,.F.);
+#1514=EDGE_LOOP('',(#1509,#1510,#1512,#1513));
+#1515=FACE_OUTER_BOUND('',#1514,.F.);
+#1517=CARTESIAN_POINT('',(-4.3E0,5.85E-1,-4.3E0));
+#1518=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1519=DIRECTION('',(1.E0,0.E0,0.E0));
+#1520=AXIS2_PLACEMENT_3D('',#1517,#1518,#1519);
+#1521=PLANE('',#1520);
+#1522=ORIENTED_EDGE('',*,*,#1497,.T.);
+#1523=ORIENTED_EDGE('',*,*,#1511,.T.);
+#1524=EDGE_LOOP('',(#1522,#1523));
+#1525=FACE_OUTER_BOUND('',#1524,.F.);
+#1527=CARTESIAN_POINT('',(1.8036E1,5.35E-1,-4.833559277371E0));
+#1528=DIRECTION('',(-1.E0,0.E0,0.E0));
+#1529=DIRECTION('',(0.E0,1.E0,0.E0));
+#1530=AXIS2_PLACEMENT_3D('',#1527,#1528,#1529);
+#1531=CYLINDRICAL_SURFACE('',#1530,1.E-1);
+#1533=ORIENTED_EDGE('',*,*,#1532,.F.);
+#1535=ORIENTED_EDGE('',*,*,#1534,.T.);
+#1536=ORIENTED_EDGE('',*,*,#1464,.T.);
+#1538=ORIENTED_EDGE('',*,*,#1537,.T.);
+#1539=EDGE_LOOP('',(#1533,#1535,#1536,#1538));
+#1540=FACE_OUTER_BOUND('',#1539,.F.);
+#1542=CARTESIAN_POINT('',(5.E0,0.E0,-5.E0));
+#1543=DIRECTION('',(0.E0,1.218693434051E-1,-9.925461516413E-1));
+#1544=DIRECTION('',(-1.E0,0.E0,0.E0));
+#1545=AXIS2_PLACEMENT_3D('',#1542,#1543,#1544);
+#1546=PLANE('',#1545);
+#1547=ORIENTED_EDGE('',*,*,#1532,.T.);
+#1549=ORIENTED_EDGE('',*,*,#1548,.F.);
+#1551=ORIENTED_EDGE('',*,*,#1550,.T.);
+#1553=ORIENTED_EDGE('',*,*,#1552,.F.);
+#1554=EDGE_LOOP('',(#1547,#1549,#1551,#1553));
+#1555=FACE_OUTER_BOUND('',#1554,.F.);
+#1557=CARTESIAN_POINT('',(-4.759994499642E0,-2.59004E0,-5.217265941575E0));
+#1558=DIRECTION('',(5.041574044985E-2,9.912839485362E-1,1.217143643511E-1));
+#1559=DIRECTION('',(0.E0,1.218693434051E-1,-9.925461516413E-1));
+#1560=AXIS2_PLACEMENT_3D('',#1557,#1558,#1559);
+#1561=CYLINDRICAL_SURFACE('',#1560,1.E-1);
+#1563=ORIENTED_EDGE('',*,*,#1562,.F.);
+#1565=ORIENTED_EDGE('',*,*,#1564,.T.);
+#1566=ORIENTED_EDGE('',*,*,#1548,.T.);
+#1568=ORIENTED_EDGE('',*,*,#1567,.T.);
+#1569=EDGE_LOOP('',(#1563,#1565,#1566,#1568));
+#1570=FACE_OUTER_BOUND('',#1569,.F.);
+#1572=CARTESIAN_POINT('',(-4.807639552073E0,3.151334031461E-1,
+-4.807639552073E0));
+#1573=DIRECTION('',(-7.018361144662E-1,1.218693434051E-1,-7.018361144662E-1));
+#1574=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#1575=AXIS2_PLACEMENT_3D('',#1572,#1573,#1574);
+#1576=PLANE('',#1575);
+#1577=ORIENTED_EDGE('',*,*,#1562,.T.);
+#1579=ORIENTED_EDGE('',*,*,#1578,.T.);
+#1581=ORIENTED_EDGE('',*,*,#1580,.T.);
+#1583=ORIENTED_EDGE('',*,*,#1582,.F.);
+#1584=EDGE_LOOP('',(#1577,#1579,#1581,#1583));
+#1585=FACE_OUTER_BOUND('',#1584,.F.);
+#1587=CARTESIAN_POINT('',(8.601382727273E0,5.35E-1,-1.8036E1));
+#1588=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#1589=DIRECTION('',(0.E0,1.E0,0.E0));
+#1590=AXIS2_PLACEMENT_3D('',#1587,#1588,#1589);
+#1591=CYLINDRICAL_SURFACE('',#1590,1.E-1);
+#1592=ORIENTED_EDGE('',*,*,#1478,.T.);
+#1594=ORIENTED_EDGE('',*,*,#1593,.T.);
+#1595=ORIENTED_EDGE('',*,*,#1578,.F.);
+#1597=ORIENTED_EDGE('',*,*,#1596,.T.);
+#1598=EDGE_LOOP('',(#1592,#1594,#1595,#1597));
+#1599=FACE_OUTER_BOUND('',#1598,.F.);
+#1601=CARTESIAN_POINT('',(-4.833559277371E0,5.35E-1,-4.601057995356E0));
+#1602=DIRECTION('',(3.826834323651E-1,0.E0,-9.238795325113E-1));
+#1603=DIRECTION('',(-9.158269509596E-1,1.317426786372E-1,-3.793479438743E-1));
+#1604=AXIS2_PLACEMENT_3D('',#1601,#1602,#1603);
+#1605=SPHERICAL_SURFACE('',#1604,1.E-1);
+#1607=ORIENTED_EDGE('',*,*,#1606,.F.);
+#1608=ORIENTED_EDGE('',*,*,#1593,.F.);
+#1610=ORIENTED_EDGE('',*,*,#1609,.F.);
+#1611=EDGE_LOOP('',(#1607,#1608,#1610));
+#1612=FACE_OUTER_BOUND('',#1611,.F.);
+#1614=CARTESIAN_POINT('',(-4.597194086251E0,2.46004E0,-4.503152327521E0));
+#1615=DIRECTION('',(-1.217143643511E-1,-9.912839485362E-1,-5.041574044985E-2));
+#1616=DIRECTION('',(-9.925461516413E-1,1.218693434051E-1,0.E0));
+#1617=AXIS2_PLACEMENT_3D('',#1614,#1615,#1616);
+#1618=CYLINDRICAL_SURFACE('',#1617,1.E-1);
+#1619=ORIENTED_EDGE('',*,*,#1580,.F.);
+#1620=ORIENTED_EDGE('',*,*,#1606,.T.);
+#1622=ORIENTED_EDGE('',*,*,#1621,.T.);
+#1624=ORIENTED_EDGE('',*,*,#1623,.F.);
+#1625=EDGE_LOOP('',(#1619,#1620,#1622,#1624));
+#1626=FACE_OUTER_BOUND('',#1625,.F.);
+#1628=CARTESIAN_POINT('',(-5.E0,0.E0,-5.E0));
+#1629=DIRECTION('',(-9.925461516413E-1,1.218693434051E-1,0.E0));
+#1630=DIRECTION('',(0.E0,0.E0,1.E0));
+#1631=AXIS2_PLACEMENT_3D('',#1628,#1629,#1630);
+#1632=PLANE('',#1631);
+#1634=ORIENTED_EDGE('',*,*,#1633,.T.);
+#1636=ORIENTED_EDGE('',*,*,#1635,.F.);
+#1638=ORIENTED_EDGE('',*,*,#1637,.T.);
+#1639=ORIENTED_EDGE('',*,*,#1621,.F.);
+#1640=EDGE_LOOP('',(#1634,#1636,#1638,#1639));
+#1641=FACE_OUTER_BOUND('',#1640,.F.);
+#1643=CARTESIAN_POINT('',(-4.833559277371E0,5.35E-1,-1.8036E1));
+#1644=DIRECTION('',(0.E0,0.E0,1.E0));
+#1645=DIRECTION('',(0.E0,1.E0,0.E0));
+#1646=AXIS2_PLACEMENT_3D('',#1643,#1644,#1645);
+#1647=CYLINDRICAL_SURFACE('',#1646,1.E-1);
+#1648=ORIENTED_EDGE('',*,*,#1633,.F.);
+#1649=ORIENTED_EDGE('',*,*,#1609,.T.);
+#1650=ORIENTED_EDGE('',*,*,#1476,.T.);
+#1652=ORIENTED_EDGE('',*,*,#1651,.T.);
+#1653=EDGE_LOOP('',(#1648,#1649,#1650,#1652));
+#1654=FACE_OUTER_BOUND('',#1653,.F.);
+#1656=CARTESIAN_POINT('',(-4.833559277371E0,5.35E-1,4.601057995356E0));
+#1657=DIRECTION('',(-5.295916689784E-1,-6.626200482157E-1,5.295916689784E-1));
+#1658=DIRECTION('',(-4.685431294435E-1,7.489557207890E-1,4.685431294435E-1));
+#1659=AXIS2_PLACEMENT_3D('',#1656,#1657,#1658);
+#1660=SPHERICAL_SURFACE('',#1659,1.E-1);
+#1662=ORIENTED_EDGE('',*,*,#1661,.F.);
+#1664=ORIENTED_EDGE('',*,*,#1663,.F.);
+#1665=ORIENTED_EDGE('',*,*,#1651,.F.);
+#1666=EDGE_LOOP('',(#1662,#1664,#1665));
+#1667=FACE_OUTER_BOUND('',#1666,.F.);
+#1669=CARTESIAN_POINT('',(-1.8036E1,5.35E-1,-8.601382727273E0));
+#1670=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#1671=DIRECTION('',(0.E0,1.E0,0.E0));
+#1672=AXIS2_PLACEMENT_3D('',#1669,#1670,#1671);
+#1673=CYLINDRICAL_SURFACE('',#1672,1.E-1);
+#1675=ORIENTED_EDGE('',*,*,#1674,.F.);
+#1676=ORIENTED_EDGE('',*,*,#1661,.T.);
+#1677=ORIENTED_EDGE('',*,*,#1474,.T.);
+#1679=ORIENTED_EDGE('',*,*,#1678,.T.);
+#1680=EDGE_LOOP('',(#1675,#1676,#1677,#1679));
+#1681=FACE_OUTER_BOUND('',#1680,.F.);
+#1683=CARTESIAN_POINT('',(-4.807639552073E0,3.151334031461E-1,
+4.807639552073E0));
+#1684=DIRECTION('',(-7.018361144662E-1,1.218693434051E-1,7.018361144662E-1));
+#1685=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#1686=AXIS2_PLACEMENT_3D('',#1683,#1684,#1685);
+#1687=PLANE('',#1686);
+#1689=ORIENTED_EDGE('',*,*,#1688,.T.);
+#1690=ORIENTED_EDGE('',*,*,#1674,.T.);
+#1692=ORIENTED_EDGE('',*,*,#1691,.T.);
+#1694=ORIENTED_EDGE('',*,*,#1693,.F.);
+#1695=EDGE_LOOP('',(#1689,#1690,#1692,#1694));
+#1696=FACE_OUTER_BOUND('',#1695,.F.);
+#1698=CARTESIAN_POINT('',(-5.217265941575E0,-2.59004E0,4.759994499642E0));
+#1699=DIRECTION('',(1.217143643511E-1,9.912839485362E-1,-5.041574044985E-2));
+#1700=DIRECTION('',(-9.925461516413E-1,1.218693434051E-1,0.E0));
+#1701=AXIS2_PLACEMENT_3D('',#1698,#1699,#1700);
+#1702=CYLINDRICAL_SURFACE('',#1701,1.E-1);
+#1703=ORIENTED_EDGE('',*,*,#1688,.F.);
+#1705=ORIENTED_EDGE('',*,*,#1704,.T.);
+#1706=ORIENTED_EDGE('',*,*,#1635,.T.);
+#1707=ORIENTED_EDGE('',*,*,#1663,.T.);
+#1708=EDGE_LOOP('',(#1703,#1705,#1706,#1707));
+#1709=FACE_OUTER_BOUND('',#1708,.F.);
+#1711=CARTESIAN_POINT('',(-4.9E0,2.46004E0,4.628578643763E0));
+#1712=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1713=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#1714=AXIS2_PLACEMENT_3D('',#1711,#1712,#1713);
+#1715=CYLINDRICAL_SURFACE('',#1714,1.E-1);
+#1717=ORIENTED_EDGE('',*,*,#1716,.F.);
+#1718=ORIENTED_EDGE('',*,*,#1704,.F.);
+#1720=ORIENTED_EDGE('',*,*,#1719,.T.);
+#1722=ORIENTED_EDGE('',*,*,#1721,.T.);
+#1723=EDGE_LOOP('',(#1717,#1718,#1720,#1722));
+#1724=FACE_OUTER_BOUND('',#1723,.F.);
+#1726=CARTESIAN_POINT('',(-5.E0,0.E0,-4.67E0));
+#1727=DIRECTION('',(-1.E0,0.E0,0.E0));
+#1728=DIRECTION('',(0.E0,0.E0,1.E0));
+#1729=AXIS2_PLACEMENT_3D('',#1726,#1727,#1728);
+#1730=PLANE('',#1729);
+#1731=ORIENTED_EDGE('',*,*,#1716,.T.);
+#1733=ORIENTED_EDGE('',*,*,#1732,.F.);
+#1735=ORIENTED_EDGE('',*,*,#1734,.F.);
+#1736=ORIENTED_EDGE('',*,*,#1637,.F.);
+#1737=EDGE_LOOP('',(#1731,#1733,#1735,#1736));
+#1738=FACE_OUTER_BOUND('',#1737,.F.);
+#1740=CARTESIAN_POINT('',(-5.E0,-1.3E-1,-4.67E0));
+#1741=DIRECTION('',(-9.925461516413E-1,-1.218693434051E-1,0.E0));
+#1742=DIRECTION('',(0.E0,0.E0,1.E0));
+#1743=AXIS2_PLACEMENT_3D('',#1740,#1741,#1742);
+#1744=PLANE('',#1743);
+#1746=ORIENTED_EDGE('',*,*,#1745,.T.);
+#1748=ORIENTED_EDGE('',*,*,#1747,.T.);
+#1750=ORIENTED_EDGE('',*,*,#1749,.F.);
+#1751=ORIENTED_EDGE('',*,*,#1732,.T.);
+#1752=EDGE_LOOP('',(#1746,#1748,#1750,#1751));
+#1753=FACE_OUTER_BOUND('',#1752,.F.);
+#1755=CARTESIAN_POINT('',(-5.217265941575E0,2.46004E0,4.759994499642E0));
+#1756=DIRECTION('',(1.217143643511E-1,-9.912839485362E-1,-5.041574044985E-2));
+#1757=DIRECTION('',(-7.018361144662E-1,-1.218693434051E-1,7.018361144662E-1));
+#1758=AXIS2_PLACEMENT_3D('',#1755,#1756,#1757);
+#1759=CYLINDRICAL_SURFACE('',#1758,1.E-1);
+#1760=ORIENTED_EDGE('',*,*,#1745,.F.);
+#1761=ORIENTED_EDGE('',*,*,#1721,.F.);
+#1763=ORIENTED_EDGE('',*,*,#1762,.T.);
+#1765=ORIENTED_EDGE('',*,*,#1764,.T.);
+#1766=EDGE_LOOP('',(#1760,#1761,#1763,#1765));
+#1767=FACE_OUTER_BOUND('',#1766,.F.);
+#1769=CARTESIAN_POINT('',(-5.E0,-1.3E-1,4.67E0));
+#1770=DIRECTION('',(-7.018361144662E-1,-1.218693434051E-1,7.018361144662E-1));
+#1771=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#1772=AXIS2_PLACEMENT_3D('',#1769,#1770,#1771);
+#1773=PLANE('',#1772);
+#1774=ORIENTED_EDGE('',*,*,#1762,.F.);
+#1776=ORIENTED_EDGE('',*,*,#1775,.T.);
+#1778=ORIENTED_EDGE('',*,*,#1777,.T.);
+#1780=ORIENTED_EDGE('',*,*,#1779,.T.);
+#1781=EDGE_LOOP('',(#1774,#1776,#1778,#1780));
+#1782=FACE_OUTER_BOUND('',#1781,.F.);
+#1784=CARTESIAN_POINT('',(-5.E0,0.E0,4.67E0));
+#1785=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#1786=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#1787=AXIS2_PLACEMENT_3D('',#1784,#1785,#1786);
+#1788=PLANE('',#1787);
+#1789=ORIENTED_EDGE('',*,*,#1719,.F.);
+#1790=ORIENTED_EDGE('',*,*,#1693,.T.);
+#1792=ORIENTED_EDGE('',*,*,#1791,.T.);
+#1793=ORIENTED_EDGE('',*,*,#1775,.F.);
+#1794=EDGE_LOOP('',(#1789,#1790,#1792,#1793));
+#1795=FACE_OUTER_BOUND('',#1794,.F.);
+#1797=CARTESIAN_POINT('',(-4.628578643763E0,2.46004E0,4.9E0));
+#1798=DIRECTION('',(0.E0,-1.E0,0.E0));
+#1799=DIRECTION('',(0.E0,0.E0,1.E0));
+#1800=AXIS2_PLACEMENT_3D('',#1797,#1798,#1799);
+#1801=CYLINDRICAL_SURFACE('',#1800,1.E-1);
+#1802=ORIENTED_EDGE('',*,*,#1791,.F.);
+#1804=ORIENTED_EDGE('',*,*,#1803,.T.);
+#1806=ORIENTED_EDGE('',*,*,#1805,.T.);
+#1808=ORIENTED_EDGE('',*,*,#1807,.F.);
+#1809=EDGE_LOOP('',(#1802,#1804,#1806,#1808));
+#1810=FACE_OUTER_BOUND('',#1809,.F.);
+#1812=CARTESIAN_POINT('',(-4.503152327521E0,2.46004E0,4.597194086251E0));
+#1813=DIRECTION('',(-5.041574044985E-2,-9.912839485362E-1,1.217143643511E-1));
+#1814=DIRECTION('',(0.E0,1.218693434051E-1,9.925461516413E-1));
+#1815=AXIS2_PLACEMENT_3D('',#1812,#1813,#1814);
+#1816=CYLINDRICAL_SURFACE('',#1815,1.E-1);
+#1817=ORIENTED_EDGE('',*,*,#1691,.F.);
+#1819=ORIENTED_EDGE('',*,*,#1818,.T.);
+#1821=ORIENTED_EDGE('',*,*,#1820,.T.);
+#1822=ORIENTED_EDGE('',*,*,#1803,.F.);
+#1823=EDGE_LOOP('',(#1817,#1819,#1821,#1822));
+#1824=FACE_OUTER_BOUND('',#1823,.F.);
+#1826=CARTESIAN_POINT('',(-4.601057995356E0,5.35E-1,4.833559277371E0));
+#1827=DIRECTION('',(-9.238795325113E-1,0.E0,-3.826834323651E-1));
+#1828=DIRECTION('',(-3.793479438743E-1,1.317426786372E-1,9.158269509596E-1));
+#1829=AXIS2_PLACEMENT_3D('',#1826,#1827,#1828);
+#1830=SPHERICAL_SURFACE('',#1829,1.E-1);
+#1831=ORIENTED_EDGE('',*,*,#1818,.F.);
+#1832=ORIENTED_EDGE('',*,*,#1678,.F.);
+#1834=ORIENTED_EDGE('',*,*,#1833,.F.);
+#1835=EDGE_LOOP('',(#1831,#1832,#1834));
+#1836=FACE_OUTER_BOUND('',#1835,.F.);
+#1838=CARTESIAN_POINT('',(-1.8036E1,5.35E-1,4.833559277371E0));
+#1839=DIRECTION('',(1.E0,0.E0,0.E0));
+#1840=DIRECTION('',(0.E0,1.E0,0.E0));
+#1841=AXIS2_PLACEMENT_3D('',#1838,#1839,#1840);
+#1842=CYLINDRICAL_SURFACE('',#1841,1.E-1);
+#1844=ORIENTED_EDGE('',*,*,#1843,.F.);
+#1845=ORIENTED_EDGE('',*,*,#1833,.T.);
+#1846=ORIENTED_EDGE('',*,*,#1472,.T.);
+#1848=ORIENTED_EDGE('',*,*,#1847,.T.);
+#1849=EDGE_LOOP('',(#1844,#1845,#1846,#1848));
+#1850=FACE_OUTER_BOUND('',#1849,.F.);
+#1852=CARTESIAN_POINT('',(-5.E0,0.E0,5.E0));
+#1853=DIRECTION('',(0.E0,1.218693434051E-1,9.925461516413E-1));
+#1854=DIRECTION('',(1.E0,0.E0,0.E0));
+#1855=AXIS2_PLACEMENT_3D('',#1852,#1853,#1854);
+#1856=PLANE('',#1855);
+#1858=ORIENTED_EDGE('',*,*,#1857,.F.);
+#1860=ORIENTED_EDGE('',*,*,#1859,.F.);
+#1861=ORIENTED_EDGE('',*,*,#1820,.F.);
+#1862=ORIENTED_EDGE('',*,*,#1843,.T.);
+#1863=EDGE_LOOP('',(#1858,#1860,#1861,#1862));
+#1864=FACE_OUTER_BOUND('',#1863,.F.);
+#1866=CARTESIAN_POINT('',(4.759994499642E0,-2.59004E0,5.217265941575E0));
+#1867=DIRECTION('',(-5.041574044985E-2,9.912839485362E-1,-1.217143643511E-1));
+#1868=DIRECTION('',(0.E0,1.218693434051E-1,9.925461516413E-1));
+#1869=AXIS2_PLACEMENT_3D('',#1866,#1867,#1868);
+#1870=CYLINDRICAL_SURFACE('',#1869,1.E-1);
+#1872=ORIENTED_EDGE('',*,*,#1871,.F.);
+#1874=ORIENTED_EDGE('',*,*,#1873,.T.);
+#1875=ORIENTED_EDGE('',*,*,#1857,.T.);
+#1877=ORIENTED_EDGE('',*,*,#1876,.T.);
+#1878=EDGE_LOOP('',(#1872,#1874,#1875,#1877));
+#1879=FACE_OUTER_BOUND('',#1878,.F.);
+#1881=CARTESIAN_POINT('',(4.807639552073E0,3.151334031461E-1,4.807639552073E0));
+#1882=DIRECTION('',(7.018361144662E-1,1.218693434051E-1,7.018361144662E-1));
+#1883=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#1884=AXIS2_PLACEMENT_3D('',#1881,#1882,#1883);
+#1885=PLANE('',#1884);
+#1887=ORIENTED_EDGE('',*,*,#1886,.T.);
+#1889=ORIENTED_EDGE('',*,*,#1888,.T.);
+#1891=ORIENTED_EDGE('',*,*,#1890,.F.);
+#1892=ORIENTED_EDGE('',*,*,#1871,.T.);
+#1893=EDGE_LOOP('',(#1887,#1889,#1891,#1892));
+#1894=FACE_OUTER_BOUND('',#1893,.F.);
+#1896=CARTESIAN_POINT('',(-8.601382727273E0,5.35E-1,1.8036E1));
+#1897=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#1898=DIRECTION('',(0.E0,1.E0,0.E0));
+#1899=AXIS2_PLACEMENT_3D('',#1896,#1897,#1898);
+#1900=CYLINDRICAL_SURFACE('',#1899,1.E-1);
+#1901=ORIENTED_EDGE('',*,*,#1886,.F.);
+#1903=ORIENTED_EDGE('',*,*,#1902,.T.);
+#1904=ORIENTED_EDGE('',*,*,#1470,.T.);
+#1906=ORIENTED_EDGE('',*,*,#1905,.T.);
+#1907=EDGE_LOOP('',(#1901,#1903,#1904,#1906));
+#1908=FACE_OUTER_BOUND('',#1907,.F.);
+#1910=CARTESIAN_POINT('',(4.601057995356E0,5.35E-1,4.833559277371E0));
+#1911=DIRECTION('',(5.295916689784E-1,-6.626200482157E-1,5.295916689784E-1));
+#1912=DIRECTION('',(4.685431294435E-1,7.489557207890E-1,4.685431294435E-1));
+#1913=AXIS2_PLACEMENT_3D('',#1910,#1911,#1912);
+#1914=SPHERICAL_SURFACE('',#1913,1.E-1);
+#1915=ORIENTED_EDGE('',*,*,#1847,.F.);
+#1916=ORIENTED_EDGE('',*,*,#1902,.F.);
+#1917=ORIENTED_EDGE('',*,*,#1876,.F.);
+#1918=EDGE_LOOP('',(#1915,#1916,#1917));
+#1919=FACE_OUTER_BOUND('',#1918,.F.);
+#1921=CARTESIAN_POINT('',(4.833559277371E0,5.35E-1,4.601057995356E0));
+#1922=DIRECTION('',(-3.826834323651E-1,0.E0,9.238795325113E-1));
+#1923=DIRECTION('',(9.158269509596E-1,1.317426786372E-1,3.793479438743E-1));
+#1924=AXIS2_PLACEMENT_3D('',#1921,#1922,#1923);
+#1925=SPHERICAL_SURFACE('',#1924,1.E-1);
+#1927=ORIENTED_EDGE('',*,*,#1926,.F.);
+#1928=ORIENTED_EDGE('',*,*,#1905,.F.);
+#1930=ORIENTED_EDGE('',*,*,#1929,.F.);
+#1931=EDGE_LOOP('',(#1927,#1928,#1930));
+#1932=FACE_OUTER_BOUND('',#1931,.F.);
+#1934=CARTESIAN_POINT('',(4.597194086251E0,2.46004E0,4.503152327521E0));
+#1935=DIRECTION('',(1.217143643511E-1,-9.912839485362E-1,5.041574044985E-2));
+#1936=DIRECTION('',(9.925461516413E-1,1.218693434051E-1,0.E0));
+#1937=AXIS2_PLACEMENT_3D('',#1934,#1935,#1936);
+#1938=CYLINDRICAL_SURFACE('',#1937,1.E-1);
+#1939=ORIENTED_EDGE('',*,*,#1888,.F.);
+#1940=ORIENTED_EDGE('',*,*,#1926,.T.);
+#1942=ORIENTED_EDGE('',*,*,#1941,.T.);
+#1944=ORIENTED_EDGE('',*,*,#1943,.F.);
+#1945=EDGE_LOOP('',(#1939,#1940,#1942,#1944));
+#1946=FACE_OUTER_BOUND('',#1945,.F.);
+#1948=CARTESIAN_POINT('',(5.E0,0.E0,5.E0));
+#1949=DIRECTION('',(9.925461516413E-1,1.218693434051E-1,0.E0));
+#1950=DIRECTION('',(0.E0,0.E0,-1.E0));
+#1951=AXIS2_PLACEMENT_3D('',#1948,#1949,#1950);
+#1952=PLANE('',#1951);
+#1954=ORIENTED_EDGE('',*,*,#1953,.F.);
+#1956=ORIENTED_EDGE('',*,*,#1955,.F.);
+#1957=ORIENTED_EDGE('',*,*,#1941,.F.);
+#1959=ORIENTED_EDGE('',*,*,#1958,.T.);
+#1960=EDGE_LOOP('',(#1954,#1956,#1957,#1959));
+#1961=FACE_OUTER_BOUND('',#1960,.F.);
+#1963=CARTESIAN_POINT('',(5.217265941575E0,-2.59004E0,-4.759994499642E0));
+#1964=DIRECTION('',(-1.217143643511E-1,9.912839485362E-1,5.041574044985E-2));
+#1965=DIRECTION('',(9.925461516413E-1,1.218693434051E-1,0.E0));
+#1966=AXIS2_PLACEMENT_3D('',#1963,#1964,#1965);
+#1967=CYLINDRICAL_SURFACE('',#1966,1.E-1);
+#1969=ORIENTED_EDGE('',*,*,#1968,.F.);
+#1971=ORIENTED_EDGE('',*,*,#1970,.T.);
+#1972=ORIENTED_EDGE('',*,*,#1953,.T.);
+#1974=ORIENTED_EDGE('',*,*,#1973,.T.);
+#1975=EDGE_LOOP('',(#1969,#1971,#1972,#1974));
+#1976=FACE_OUTER_BOUND('',#1975,.F.);
+#1978=CARTESIAN_POINT('',(4.807639552073E0,3.151334031461E-1,
+-4.807639552073E0));
+#1979=DIRECTION('',(7.018361144662E-1,1.218693434051E-1,-7.018361144662E-1));
+#1980=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#1981=AXIS2_PLACEMENT_3D('',#1978,#1979,#1980);
+#1982=PLANE('',#1981);
+#1984=ORIENTED_EDGE('',*,*,#1983,.T.);
+#1986=ORIENTED_EDGE('',*,*,#1985,.T.);
+#1988=ORIENTED_EDGE('',*,*,#1987,.F.);
+#1989=ORIENTED_EDGE('',*,*,#1968,.T.);
+#1990=EDGE_LOOP('',(#1984,#1986,#1988,#1989));
+#1991=FACE_OUTER_BOUND('',#1990,.F.);
+#1993=CARTESIAN_POINT('',(1.8036E1,5.35E-1,8.601382727273E0));
+#1994=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#1995=DIRECTION('',(0.E0,1.E0,0.E0));
+#1996=AXIS2_PLACEMENT_3D('',#1993,#1994,#1995);
+#1997=CYLINDRICAL_SURFACE('',#1996,1.E-1);
+#1998=ORIENTED_EDGE('',*,*,#1983,.F.);
+#2000=ORIENTED_EDGE('',*,*,#1999,.T.);
+#2001=ORIENTED_EDGE('',*,*,#1466,.T.);
+#2003=ORIENTED_EDGE('',*,*,#2002,.T.);
+#2004=EDGE_LOOP('',(#1998,#2000,#2001,#2003));
+#2005=FACE_OUTER_BOUND('',#2004,.F.);
+#2007=CARTESIAN_POINT('',(4.833559277371E0,5.35E-1,-4.601057995356E0));
+#2008=DIRECTION('',(5.295916689784E-1,-6.626200482157E-1,-5.295916689784E-1));
+#2009=DIRECTION('',(4.685431294435E-1,7.489557207890E-1,-4.685431294435E-1));
+#2010=AXIS2_PLACEMENT_3D('',#2007,#2008,#2009);
+#2011=SPHERICAL_SURFACE('',#2010,1.E-1);
+#2013=ORIENTED_EDGE('',*,*,#2012,.F.);
+#2014=ORIENTED_EDGE('',*,*,#1999,.F.);
+#2015=ORIENTED_EDGE('',*,*,#1973,.F.);
+#2016=EDGE_LOOP('',(#2013,#2014,#2015));
+#2017=FACE_OUTER_BOUND('',#2016,.F.);
+#2019=CARTESIAN_POINT('',(4.833559277371E0,5.35E-1,1.8036E1));
+#2020=DIRECTION('',(0.E0,0.E0,-1.E0));
+#2021=DIRECTION('',(0.E0,1.E0,0.E0));
+#2022=AXIS2_PLACEMENT_3D('',#2019,#2020,#2021);
+#2023=CYLINDRICAL_SURFACE('',#2022,1.E-1);
+#2024=ORIENTED_EDGE('',*,*,#1958,.F.);
+#2025=ORIENTED_EDGE('',*,*,#1929,.T.);
+#2026=ORIENTED_EDGE('',*,*,#1468,.T.);
+#2027=ORIENTED_EDGE('',*,*,#2012,.T.);
+#2028=EDGE_LOOP('',(#2024,#2025,#2026,#2027));
+#2029=FACE_OUTER_BOUND('',#2028,.F.);
+#2031=CARTESIAN_POINT('',(4.601057995356E0,5.35E-1,-4.833559277371E0));
+#2032=DIRECTION('',(9.238795325113E-1,0.E0,3.826834323651E-1));
+#2033=DIRECTION('',(3.793479438743E-1,1.317426786372E-1,-9.158269509596E-1));
+#2034=AXIS2_PLACEMENT_3D('',#2031,#2032,#2033);
+#2035=SPHERICAL_SURFACE('',#2034,1.E-1);
+#2037=ORIENTED_EDGE('',*,*,#2036,.F.);
+#2038=ORIENTED_EDGE('',*,*,#2002,.F.);
+#2039=ORIENTED_EDGE('',*,*,#1534,.F.);
+#2040=EDGE_LOOP('',(#2037,#2038,#2039));
+#2041=FACE_OUTER_BOUND('',#2040,.F.);
+#2043=CARTESIAN_POINT('',(4.503152327521E0,2.46004E0,-4.597194086251E0));
+#2044=DIRECTION('',(5.041574044985E-2,-9.912839485362E-1,-1.217143643511E-1));
+#2045=DIRECTION('',(0.E0,1.218693434051E-1,-9.925461516413E-1));
+#2046=AXIS2_PLACEMENT_3D('',#2043,#2044,#2045);
+#2047=CYLINDRICAL_SURFACE('',#2046,1.E-1);
+#2048=ORIENTED_EDGE('',*,*,#1985,.F.);
+#2049=ORIENTED_EDGE('',*,*,#2036,.T.);
+#2050=ORIENTED_EDGE('',*,*,#1552,.T.);
+#2052=ORIENTED_EDGE('',*,*,#2051,.F.);
+#2053=EDGE_LOOP('',(#2048,#2049,#2050,#2052));
+#2054=FACE_OUTER_BOUND('',#2053,.F.);
+#2056=CARTESIAN_POINT('',(4.628578643763E0,2.46004E0,-4.9E0));
+#2057=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2058=DIRECTION('',(0.E0,0.E0,-1.E0));
+#2059=AXIS2_PLACEMENT_3D('',#2056,#2057,#2058);
+#2060=CYLINDRICAL_SURFACE('',#2059,1.E-1);
+#2062=ORIENTED_EDGE('',*,*,#2061,.F.);
+#2063=ORIENTED_EDGE('',*,*,#2051,.T.);
+#2065=ORIENTED_EDGE('',*,*,#2064,.T.);
+#2067=ORIENTED_EDGE('',*,*,#2066,.F.);
+#2068=EDGE_LOOP('',(#2062,#2063,#2065,#2067));
+#2069=FACE_OUTER_BOUND('',#2068,.F.);
+#2071=CARTESIAN_POINT('',(5.E0,0.E0,-4.67E0));
+#2072=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#2073=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#2074=AXIS2_PLACEMENT_3D('',#2071,#2072,#2073);
+#2075=PLANE('',#2074);
+#2076=ORIENTED_EDGE('',*,*,#2061,.T.);
+#2078=ORIENTED_EDGE('',*,*,#2077,.F.);
+#2080=ORIENTED_EDGE('',*,*,#2079,.F.);
+#2081=ORIENTED_EDGE('',*,*,#1987,.T.);
+#2082=EDGE_LOOP('',(#2076,#2078,#2080,#2081));
+#2083=FACE_OUTER_BOUND('',#2082,.F.);
+#2085=CARTESIAN_POINT('',(5.E0,-1.3E-1,-4.67E0));
+#2086=DIRECTION('',(7.018361144662E-1,-1.218693434051E-1,-7.018361144662E-1));
+#2087=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#2088=AXIS2_PLACEMENT_3D('',#2085,#2086,#2087);
+#2089=PLANE('',#2088);
+#2091=ORIENTED_EDGE('',*,*,#2090,.T.);
+#2093=ORIENTED_EDGE('',*,*,#2092,.T.);
+#2095=ORIENTED_EDGE('',*,*,#2094,.F.);
+#2096=ORIENTED_EDGE('',*,*,#2077,.T.);
+#2097=EDGE_LOOP('',(#2091,#2093,#2095,#2096));
+#2098=FACE_OUTER_BOUND('',#2097,.F.);
+#2100=CARTESIAN_POINT('',(4.759994499642E0,2.46004E0,-5.217265941575E0));
+#2101=DIRECTION('',(-5.041574044985E-2,-9.912839485362E-1,1.217143643511E-1));
+#2102=DIRECTION('',(0.E0,-1.218693434051E-1,-9.925461516413E-1));
+#2103=AXIS2_PLACEMENT_3D('',#2100,#2101,#2102);
+#2104=CYLINDRICAL_SURFACE('',#2103,1.E-1);
+#2106=ORIENTED_EDGE('',*,*,#2105,.T.);
+#2108=ORIENTED_EDGE('',*,*,#2107,.T.);
+#2109=ORIENTED_EDGE('',*,*,#2090,.F.);
+#2110=ORIENTED_EDGE('',*,*,#2066,.T.);
+#2111=EDGE_LOOP('',(#2106,#2108,#2109,#2110));
+#2112=FACE_OUTER_BOUND('',#2111,.F.);
+#2114=CARTESIAN_POINT('',(4.67E0,-1.3E-1,-5.E0));
+#2115=DIRECTION('',(0.E0,-1.218693434051E-1,-9.925461516413E-1));
+#2116=DIRECTION('',(-1.E0,0.E0,0.E0));
+#2117=AXIS2_PLACEMENT_3D('',#2114,#2115,#2116);
+#2118=PLANE('',#2117);
+#2120=ORIENTED_EDGE('',*,*,#2119,.T.);
+#2121=ORIENTED_EDGE('',*,*,#2105,.F.);
+#2123=ORIENTED_EDGE('',*,*,#2122,.T.);
+#2125=ORIENTED_EDGE('',*,*,#2124,.T.);
+#2126=EDGE_LOOP('',(#2120,#2121,#2123,#2125));
+#2127=FACE_OUTER_BOUND('',#2126,.F.);
+#2129=CARTESIAN_POINT('',(-1.8036E1,-6.65E-1,-4.833559277371E0));
+#2130=DIRECTION('',(1.E0,0.E0,0.E0));
+#2131=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2132=AXIS2_PLACEMENT_3D('',#2129,#2130,#2131);
+#2133=CYLINDRICAL_SURFACE('',#2132,1.E-1);
+#2134=ORIENTED_EDGE('',*,*,#2119,.F.);
+#2136=ORIENTED_EDGE('',*,*,#2135,.T.);
+#2138=ORIENTED_EDGE('',*,*,#2137,.T.);
+#2140=ORIENTED_EDGE('',*,*,#2139,.T.);
+#2141=EDGE_LOOP('',(#2134,#2136,#2138,#2140));
+#2142=FACE_OUTER_BOUND('',#2141,.F.);
+#2144=CARTESIAN_POINT('',(-4.601057995356E0,-6.65E-1,-4.833559277371E0));
+#2145=DIRECTION('',(-9.238795325113E-1,0.E0,3.826834323651E-1));
+#2146=DIRECTION('',(-3.793479438743E-1,-1.317426786372E-1,-9.158269509596E-1));
+#2147=AXIS2_PLACEMENT_3D('',#2144,#2145,#2146);
+#2148=SPHERICAL_SURFACE('',#2147,1.E-1);
+#2150=ORIENTED_EDGE('',*,*,#2149,.F.);
+#2152=ORIENTED_EDGE('',*,*,#2151,.F.);
+#2153=ORIENTED_EDGE('',*,*,#2135,.F.);
+#2154=EDGE_LOOP('',(#2150,#2152,#2153));
+#2155=FACE_OUTER_BOUND('',#2154,.F.);
+#2157=CARTESIAN_POINT('',(-4.759994499642E0,2.46004E0,-5.217265941575E0));
+#2158=DIRECTION('',(5.041574044985E-2,-9.912839485362E-1,1.217143643511E-1));
+#2159=DIRECTION('',(-7.018361144662E-1,-1.218693434051E-1,-7.018361144662E-1));
+#2160=AXIS2_PLACEMENT_3D('',#2157,#2158,#2159);
+#2161=CYLINDRICAL_SURFACE('',#2160,1.E-1);
+#2162=ORIENTED_EDGE('',*,*,#2124,.F.);
+#2164=ORIENTED_EDGE('',*,*,#2163,.F.);
+#2166=ORIENTED_EDGE('',*,*,#2165,.T.);
+#2167=ORIENTED_EDGE('',*,*,#2149,.T.);
+#2168=EDGE_LOOP('',(#2162,#2164,#2166,#2167));
+#2169=FACE_OUTER_BOUND('',#2168,.F.);
+#2171=CARTESIAN_POINT('',(-4.628578643763E0,2.46004E0,-4.9E0));
+#2172=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2173=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#2174=AXIS2_PLACEMENT_3D('',#2171,#2172,#2173);
+#2175=CYLINDRICAL_SURFACE('',#2174,1.E-1);
+#2177=ORIENTED_EDGE('',*,*,#2176,.F.);
+#2178=ORIENTED_EDGE('',*,*,#1564,.F.);
+#2180=ORIENTED_EDGE('',*,*,#2179,.T.);
+#2181=ORIENTED_EDGE('',*,*,#2163,.T.);
+#2182=EDGE_LOOP('',(#2177,#2178,#2180,#2181));
+#2183=FACE_OUTER_BOUND('',#2182,.F.);
+#2185=CARTESIAN_POINT('',(4.67E0,0.E0,-5.E0));
+#2186=DIRECTION('',(0.E0,0.E0,-1.E0));
+#2187=DIRECTION('',(-1.E0,0.E0,0.E0));
+#2188=AXIS2_PLACEMENT_3D('',#2185,#2186,#2187);
+#2189=PLANE('',#2188);
+#2190=ORIENTED_EDGE('',*,*,#2064,.F.);
+#2191=ORIENTED_EDGE('',*,*,#1550,.F.);
+#2192=ORIENTED_EDGE('',*,*,#2176,.T.);
+#2193=ORIENTED_EDGE('',*,*,#2122,.F.);
+#2194=EDGE_LOOP('',(#2190,#2191,#2192,#2193));
+#2195=FACE_OUTER_BOUND('',#2194,.F.);
+#2197=CARTESIAN_POINT('',(-4.67E0,0.E0,-5.E0));
+#2198=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#2199=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#2200=AXIS2_PLACEMENT_3D('',#2197,#2198,#2199);
+#2201=PLANE('',#2200);
+#2203=ORIENTED_EDGE('',*,*,#2202,.T.);
+#2205=ORIENTED_EDGE('',*,*,#2204,.F.);
+#2206=ORIENTED_EDGE('',*,*,#2179,.F.);
+#2207=ORIENTED_EDGE('',*,*,#1582,.T.);
+#2208=EDGE_LOOP('',(#2203,#2205,#2206,#2207));
+#2209=FACE_OUTER_BOUND('',#2208,.F.);
+#2211=CARTESIAN_POINT('',(-4.9E0,2.46004E0,-4.628578643763E0));
+#2212=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2213=DIRECTION('',(-1.E0,0.E0,0.E0));
+#2214=AXIS2_PLACEMENT_3D('',#2211,#2212,#2213);
+#2215=CYLINDRICAL_SURFACE('',#2214,1.E-1);
+#2216=ORIENTED_EDGE('',*,*,#2202,.F.);
+#2217=ORIENTED_EDGE('',*,*,#1623,.T.);
+#2218=ORIENTED_EDGE('',*,*,#1734,.T.);
+#2220=ORIENTED_EDGE('',*,*,#2219,.T.);
+#2221=EDGE_LOOP('',(#2216,#2217,#2218,#2220));
+#2222=FACE_OUTER_BOUND('',#2221,.F.);
+#2224=CARTESIAN_POINT('',(-5.217265941575E0,2.46004E0,-4.759994499642E0));
+#2225=DIRECTION('',(1.217143643511E-1,-9.912839485362E-1,5.041574044985E-2));
+#2226=DIRECTION('',(-9.925461516413E-1,-1.218693434051E-1,0.E0));
+#2227=AXIS2_PLACEMENT_3D('',#2224,#2225,#2226);
+#2228=CYLINDRICAL_SURFACE('',#2227,1.E-1);
+#2230=ORIENTED_EDGE('',*,*,#2229,.F.);
+#2231=ORIENTED_EDGE('',*,*,#2219,.F.);
+#2232=ORIENTED_EDGE('',*,*,#1749,.T.);
+#2234=ORIENTED_EDGE('',*,*,#2233,.T.);
+#2235=EDGE_LOOP('',(#2230,#2231,#2232,#2234));
+#2236=FACE_OUTER_BOUND('',#2235,.F.);
+#2238=CARTESIAN_POINT('',(-4.67E0,-1.3E-1,-5.E0));
+#2239=DIRECTION('',(-7.018361144662E-1,-1.218693434051E-1,-7.018361144662E-1));
+#2240=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#2241=AXIS2_PLACEMENT_3D('',#2238,#2239,#2240);
+#2242=PLANE('',#2241);
+#2243=ORIENTED_EDGE('',*,*,#2229,.T.);
+#2245=ORIENTED_EDGE('',*,*,#2244,.T.);
+#2246=ORIENTED_EDGE('',*,*,#2165,.F.);
+#2247=ORIENTED_EDGE('',*,*,#2204,.T.);
+#2248=EDGE_LOOP('',(#2243,#2245,#2246,#2247));
+#2249=FACE_OUTER_BOUND('',#2248,.F.);
+#2251=CARTESIAN_POINT('',(-1.8036E1,-6.65E-1,8.601382727273E0));
+#2252=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#2253=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2254=AXIS2_PLACEMENT_3D('',#2251,#2252,#2253);
+#2255=CYLINDRICAL_SURFACE('',#2254,1.E-1);
+#2256=ORIENTED_EDGE('',*,*,#2244,.F.);
+#2258=ORIENTED_EDGE('',*,*,#2257,.T.);
+#2260=ORIENTED_EDGE('',*,*,#2259,.T.);
+#2261=ORIENTED_EDGE('',*,*,#2151,.T.);
+#2262=EDGE_LOOP('',(#2256,#2258,#2260,#2261));
+#2263=FACE_OUTER_BOUND('',#2262,.F.);
+#2265=CARTESIAN_POINT('',(-4.833559277371E0,-6.65E-1,-4.601057995356E0));
+#2266=DIRECTION('',(-5.295916689784E-1,6.626200482157E-1,-5.295916689784E-1));
+#2267=DIRECTION('',(-4.685431294435E-1,-7.489557207890E-1,-4.685431294435E-1));
+#2268=AXIS2_PLACEMENT_3D('',#2265,#2266,#2267);
+#2269=SPHERICAL_SURFACE('',#2268,1.E-1);
+#2270=ORIENTED_EDGE('',*,*,#2257,.F.);
+#2271=ORIENTED_EDGE('',*,*,#2233,.F.);
+#2273=ORIENTED_EDGE('',*,*,#2272,.F.);
+#2274=EDGE_LOOP('',(#2270,#2271,#2273));
+#2275=FACE_OUTER_BOUND('',#2274,.F.);
+#2277=CARTESIAN_POINT('',(-4.833559277371E0,-6.65E-1,1.8036E1));
+#2278=DIRECTION('',(0.E0,0.E0,-1.E0));
+#2279=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2280=AXIS2_PLACEMENT_3D('',#2277,#2278,#2279);
+#2281=CYLINDRICAL_SURFACE('',#2280,1.E-1);
+#2282=ORIENTED_EDGE('',*,*,#1747,.F.);
+#2284=ORIENTED_EDGE('',*,*,#2283,.T.);
+#2286=ORIENTED_EDGE('',*,*,#2285,.T.);
+#2287=ORIENTED_EDGE('',*,*,#2272,.T.);
+#2288=EDGE_LOOP('',(#2282,#2284,#2286,#2287));
+#2289=FACE_OUTER_BOUND('',#2288,.F.);
+#2291=CARTESIAN_POINT('',(-4.833559277371E0,-6.65E-1,4.601057995356E0));
+#2292=DIRECTION('',(3.826834323651E-1,0.E0,9.238795325113E-1));
+#2293=DIRECTION('',(-9.158269509596E-1,-1.317426786372E-1,3.793479438743E-1));
+#2294=AXIS2_PLACEMENT_3D('',#2291,#2292,#2293);
+#2295=SPHERICAL_SURFACE('',#2294,1.E-1);
+#2296=ORIENTED_EDGE('',*,*,#2283,.F.);
+#2297=ORIENTED_EDGE('',*,*,#1764,.F.);
+#2299=ORIENTED_EDGE('',*,*,#2298,.F.);
+#2300=EDGE_LOOP('',(#2296,#2297,#2299));
+#2301=FACE_OUTER_BOUND('',#2300,.F.);
+#2303=CARTESIAN_POINT('',(8.601382727273E0,-6.65E-1,1.8036E1));
+#2304=DIRECTION('',(-7.071067811865E-1,0.E0,-7.071067811865E-1));
+#2305=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2306=AXIS2_PLACEMENT_3D('',#2303,#2304,#2305);
+#2307=CYLINDRICAL_SURFACE('',#2306,1.E-1);
+#2309=ORIENTED_EDGE('',*,*,#2308,.T.);
+#2310=ORIENTED_EDGE('',*,*,#2298,.T.);
+#2311=ORIENTED_EDGE('',*,*,#1779,.F.);
+#2313=ORIENTED_EDGE('',*,*,#2312,.T.);
+#2314=EDGE_LOOP('',(#2309,#2310,#2311,#2313));
+#2315=FACE_OUTER_BOUND('',#2314,.F.);
+#2317=CARTESIAN_POINT('',(0.E0,-7.65E-1,0.E0));
+#2318=DIRECTION('',(0.E0,1.E0,0.E0));
+#2319=DIRECTION('',(1.E0,0.E0,0.E0));
+#2320=AXIS2_PLACEMENT_3D('',#2317,#2318,#2319);
+#2321=PLANE('',#2320);
+#2323=ORIENTED_EDGE('',*,*,#2322,.F.);
+#2325=ORIENTED_EDGE('',*,*,#2324,.F.);
+#2327=ORIENTED_EDGE('',*,*,#2326,.F.);
+#2329=ORIENTED_EDGE('',*,*,#2328,.F.);
+#2330=ORIENTED_EDGE('',*,*,#2137,.F.);
+#2331=ORIENTED_EDGE('',*,*,#2259,.F.);
+#2332=ORIENTED_EDGE('',*,*,#2285,.F.);
+#2333=ORIENTED_EDGE('',*,*,#2308,.F.);
+#2334=EDGE_LOOP('',(#2323,#2325,#2327,#2329,#2330,#2331,#2332,#2333));
+#2335=FACE_OUTER_BOUND('',#2334,.F.);
+#2337=CARTESIAN_POINT('',(1.8036E1,-6.65E-1,4.833559277371E0));
+#2338=DIRECTION('',(-1.E0,0.E0,0.E0));
+#2339=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2340=AXIS2_PLACEMENT_3D('',#2337,#2338,#2339);
+#2341=CYLINDRICAL_SURFACE('',#2340,1.E-1);
+#2343=ORIENTED_EDGE('',*,*,#2342,.F.);
+#2345=ORIENTED_EDGE('',*,*,#2344,.T.);
+#2346=ORIENTED_EDGE('',*,*,#2322,.T.);
+#2348=ORIENTED_EDGE('',*,*,#2347,.T.);
+#2349=EDGE_LOOP('',(#2343,#2345,#2346,#2348));
+#2350=FACE_OUTER_BOUND('',#2349,.F.);
+#2352=CARTESIAN_POINT('',(-4.67E0,-1.3E-1,5.E0));
+#2353=DIRECTION('',(0.E0,-1.218693434051E-1,9.925461516413E-1));
+#2354=DIRECTION('',(1.E0,0.E0,0.E0));
+#2355=AXIS2_PLACEMENT_3D('',#2352,#2353,#2354);
+#2356=PLANE('',#2355);
+#2357=ORIENTED_EDGE('',*,*,#2342,.T.);
+#2359=ORIENTED_EDGE('',*,*,#2358,.F.);
+#2361=ORIENTED_EDGE('',*,*,#2360,.T.);
+#2363=ORIENTED_EDGE('',*,*,#2362,.T.);
+#2364=EDGE_LOOP('',(#2357,#2359,#2361,#2363));
+#2365=FACE_OUTER_BOUND('',#2364,.F.);
+#2367=CARTESIAN_POINT('',(-4.759994499642E0,2.46004E0,5.217265941575E0));
+#2368=DIRECTION('',(5.041574044985E-2,-9.912839485362E-1,-1.217143643511E-1));
+#2369=DIRECTION('',(0.E0,-1.218693434051E-1,9.925461516413E-1));
+#2370=AXIS2_PLACEMENT_3D('',#2367,#2368,#2369);
+#2371=CYLINDRICAL_SURFACE('',#2370,1.E-1);
+#2372=ORIENTED_EDGE('',*,*,#2358,.T.);
+#2374=ORIENTED_EDGE('',*,*,#2373,.T.);
+#2375=ORIENTED_EDGE('',*,*,#1777,.F.);
+#2376=ORIENTED_EDGE('',*,*,#1807,.T.);
+#2377=EDGE_LOOP('',(#2372,#2374,#2375,#2376));
+#2378=FACE_OUTER_BOUND('',#2377,.F.);
+#2380=CARTESIAN_POINT('',(-4.601057995356E0,-6.65E-1,4.833559277371E0));
+#2381=DIRECTION('',(-5.295916689784E-1,6.626200482157E-1,5.295916689784E-1));
+#2382=DIRECTION('',(-4.685431294435E-1,-7.489557207890E-1,4.685431294435E-1));
+#2383=AXIS2_PLACEMENT_3D('',#2380,#2381,#2382);
+#2384=SPHERICAL_SURFACE('',#2383,1.E-1);
+#2385=ORIENTED_EDGE('',*,*,#2312,.F.);
+#2386=ORIENTED_EDGE('',*,*,#2373,.F.);
+#2387=ORIENTED_EDGE('',*,*,#2347,.F.);
+#2388=EDGE_LOOP('',(#2385,#2386,#2387));
+#2389=FACE_OUTER_BOUND('',#2388,.F.);
+#2391=CARTESIAN_POINT('',(-4.67E0,0.E0,5.E0));
+#2392=DIRECTION('',(0.E0,0.E0,1.E0));
+#2393=DIRECTION('',(1.E0,0.E0,0.E0));
+#2394=AXIS2_PLACEMENT_3D('',#2391,#2392,#2393);
+#2395=PLANE('',#2394);
+#2397=ORIENTED_EDGE('',*,*,#2396,.T.);
+#2398=ORIENTED_EDGE('',*,*,#2360,.F.);
+#2399=ORIENTED_EDGE('',*,*,#1805,.F.);
+#2400=ORIENTED_EDGE('',*,*,#1859,.T.);
+#2401=EDGE_LOOP('',(#2397,#2398,#2399,#2400));
+#2402=FACE_OUTER_BOUND('',#2401,.F.);
+#2404=CARTESIAN_POINT('',(4.628578643763E0,2.46004E0,4.9E0));
+#2405=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2406=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#2407=AXIS2_PLACEMENT_3D('',#2404,#2405,#2406);
+#2408=CYLINDRICAL_SURFACE('',#2407,1.E-1);
+#2409=ORIENTED_EDGE('',*,*,#2396,.F.);
+#2410=ORIENTED_EDGE('',*,*,#1873,.F.);
+#2412=ORIENTED_EDGE('',*,*,#2411,.T.);
+#2414=ORIENTED_EDGE('',*,*,#2413,.T.);
+#2415=EDGE_LOOP('',(#2409,#2410,#2412,#2414));
+#2416=FACE_OUTER_BOUND('',#2415,.F.);
+#2418=CARTESIAN_POINT('',(4.67E0,0.E0,5.E0));
+#2419=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#2420=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#2421=AXIS2_PLACEMENT_3D('',#2418,#2419,#2420);
+#2422=PLANE('',#2421);
+#2424=ORIENTED_EDGE('',*,*,#2423,.T.);
+#2426=ORIENTED_EDGE('',*,*,#2425,.T.);
+#2427=ORIENTED_EDGE('',*,*,#2411,.F.);
+#2428=ORIENTED_EDGE('',*,*,#1890,.T.);
+#2429=EDGE_LOOP('',(#2424,#2426,#2427,#2428));
+#2430=FACE_OUTER_BOUND('',#2429,.F.);
+#2432=CARTESIAN_POINT('',(4.9E0,2.46004E0,4.628578643763E0));
+#2433=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2434=DIRECTION('',(1.E0,0.E0,0.E0));
+#2435=AXIS2_PLACEMENT_3D('',#2432,#2433,#2434);
+#2436=CYLINDRICAL_SURFACE('',#2435,1.E-1);
+#2437=ORIENTED_EDGE('',*,*,#2423,.F.);
+#2438=ORIENTED_EDGE('',*,*,#1943,.T.);
+#2440=ORIENTED_EDGE('',*,*,#2439,.T.);
+#2442=ORIENTED_EDGE('',*,*,#2441,.F.);
+#2443=EDGE_LOOP('',(#2437,#2438,#2440,#2442));
+#2444=FACE_OUTER_BOUND('',#2443,.F.);
+#2446=CARTESIAN_POINT('',(5.E0,0.E0,4.67E0));
+#2447=DIRECTION('',(1.E0,0.E0,0.E0));
+#2448=DIRECTION('',(0.E0,0.E0,-1.E0));
+#2449=AXIS2_PLACEMENT_3D('',#2446,#2447,#2448);
+#2450=PLANE('',#2449);
+#2452=ORIENTED_EDGE('',*,*,#2451,.T.);
+#2454=ORIENTED_EDGE('',*,*,#2453,.F.);
+#2455=ORIENTED_EDGE('',*,*,#2439,.F.);
+#2456=ORIENTED_EDGE('',*,*,#1955,.T.);
+#2457=EDGE_LOOP('',(#2452,#2454,#2455,#2456));
+#2458=FACE_OUTER_BOUND('',#2457,.F.);
+#2460=CARTESIAN_POINT('',(4.9E0,2.46004E0,-4.628578643763E0));
+#2461=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2462=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#2463=AXIS2_PLACEMENT_3D('',#2460,#2461,#2462);
+#2464=CYLINDRICAL_SURFACE('',#2463,1.E-1);
+#2465=ORIENTED_EDGE('',*,*,#2451,.F.);
+#2466=ORIENTED_EDGE('',*,*,#1970,.F.);
+#2467=ORIENTED_EDGE('',*,*,#2079,.T.);
+#2469=ORIENTED_EDGE('',*,*,#2468,.T.);
+#2470=EDGE_LOOP('',(#2465,#2466,#2467,#2469));
+#2471=FACE_OUTER_BOUND('',#2470,.F.);
+#2473=CARTESIAN_POINT('',(5.217265941575E0,2.46004E0,-4.759994499642E0));
+#2474=DIRECTION('',(-1.217143643511E-1,-9.912839485362E-1,5.041574044985E-2));
+#2475=DIRECTION('',(7.018361144662E-1,-1.218693434051E-1,-7.018361144662E-1));
+#2476=AXIS2_PLACEMENT_3D('',#2473,#2474,#2475);
+#2477=CYLINDRICAL_SURFACE('',#2476,1.E-1);
+#2479=ORIENTED_EDGE('',*,*,#2478,.F.);
+#2480=ORIENTED_EDGE('',*,*,#2468,.F.);
+#2481=ORIENTED_EDGE('',*,*,#2094,.T.);
+#2483=ORIENTED_EDGE('',*,*,#2482,.T.);
+#2484=EDGE_LOOP('',(#2479,#2480,#2481,#2483));
+#2485=FACE_OUTER_BOUND('',#2484,.F.);
+#2487=CARTESIAN_POINT('',(5.E0,-1.3E-1,4.67E0));
+#2488=DIRECTION('',(9.925461516413E-1,-1.218693434051E-1,0.E0));
+#2489=DIRECTION('',(0.E0,0.E0,-1.E0));
+#2490=AXIS2_PLACEMENT_3D('',#2487,#2488,#2489);
+#2491=PLANE('',#2490);
+#2493=ORIENTED_EDGE('',*,*,#2492,.T.);
+#2495=ORIENTED_EDGE('',*,*,#2494,.F.);
+#2496=ORIENTED_EDGE('',*,*,#2453,.T.);
+#2497=ORIENTED_EDGE('',*,*,#2478,.T.);
+#2498=EDGE_LOOP('',(#2493,#2495,#2496,#2497));
+#2499=FACE_OUTER_BOUND('',#2498,.F.);
+#2501=CARTESIAN_POINT('',(4.833559277371E0,-6.65E-1,-1.8036E1));
+#2502=DIRECTION('',(0.E0,0.E0,1.E0));
+#2503=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2504=AXIS2_PLACEMENT_3D('',#2501,#2502,#2503);
+#2505=CYLINDRICAL_SURFACE('',#2504,1.E-1);
+#2506=ORIENTED_EDGE('',*,*,#2492,.F.);
+#2508=ORIENTED_EDGE('',*,*,#2507,.T.);
+#2509=ORIENTED_EDGE('',*,*,#2326,.T.);
+#2511=ORIENTED_EDGE('',*,*,#2510,.T.);
+#2512=EDGE_LOOP('',(#2506,#2508,#2509,#2511));
+#2513=FACE_OUTER_BOUND('',#2512,.F.);
+#2515=CARTESIAN_POINT('',(4.833559277371E0,-6.65E-1,-4.601057995356E0));
+#2516=DIRECTION('',(-3.826834323651E-1,0.E0,-9.238795325113E-1));
+#2517=DIRECTION('',(9.158269509596E-1,-1.317426786372E-1,-3.793479438743E-1));
+#2518=AXIS2_PLACEMENT_3D('',#2515,#2516,#2517);
+#2519=SPHERICAL_SURFACE('',#2518,1.E-1);
+#2520=ORIENTED_EDGE('',*,*,#2482,.F.);
+#2522=ORIENTED_EDGE('',*,*,#2521,.F.);
+#2523=ORIENTED_EDGE('',*,*,#2507,.F.);
+#2524=EDGE_LOOP('',(#2520,#2522,#2523));
+#2525=FACE_OUTER_BOUND('',#2524,.F.);
+#2527=CARTESIAN_POINT('',(-8.601382727273E0,-6.65E-1,-1.8036E1));
+#2528=DIRECTION('',(7.071067811865E-1,0.E0,7.071067811865E-1));
+#2529=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2530=AXIS2_PLACEMENT_3D('',#2527,#2528,#2529);
+#2531=CYLINDRICAL_SURFACE('',#2530,1.E-1);
+#2532=ORIENTED_EDGE('',*,*,#2328,.T.);
+#2533=ORIENTED_EDGE('',*,*,#2521,.T.);
+#2534=ORIENTED_EDGE('',*,*,#2092,.F.);
+#2536=ORIENTED_EDGE('',*,*,#2535,.T.);
+#2537=EDGE_LOOP('',(#2532,#2533,#2534,#2536));
+#2538=FACE_OUTER_BOUND('',#2537,.F.);
+#2540=CARTESIAN_POINT('',(4.601057995356E0,-6.65E-1,-4.833559277371E0));
+#2541=DIRECTION('',(5.295916689784E-1,6.626200482157E-1,-5.295916689784E-1));
+#2542=DIRECTION('',(4.685431294435E-1,-7.489557207890E-1,-4.685431294435E-1));
+#2543=AXIS2_PLACEMENT_3D('',#2540,#2541,#2542);
+#2544=SPHERICAL_SURFACE('',#2543,1.E-1);
+#2545=ORIENTED_EDGE('',*,*,#2535,.F.);
+#2546=ORIENTED_EDGE('',*,*,#2107,.F.);
+#2547=ORIENTED_EDGE('',*,*,#2139,.F.);
+#2548=EDGE_LOOP('',(#2545,#2546,#2547));
+#2549=FACE_OUTER_BOUND('',#2548,.F.);
+#2551=CARTESIAN_POINT('',(4.833559277371E0,-6.65E-1,4.601057995356E0));
+#2552=DIRECTION('',(5.295916689784E-1,6.626200482157E-1,5.295916689784E-1));
+#2553=DIRECTION('',(4.685431294435E-1,-7.489557207890E-1,4.685431294435E-1));
+#2554=AXIS2_PLACEMENT_3D('',#2551,#2552,#2553);
+#2555=SPHERICAL_SURFACE('',#2554,1.E-1);
+#2557=ORIENTED_EDGE('',*,*,#2556,.F.);
+#2559=ORIENTED_EDGE('',*,*,#2558,.F.);
+#2560=ORIENTED_EDGE('',*,*,#2510,.F.);
+#2561=EDGE_LOOP('',(#2557,#2559,#2560));
+#2562=FACE_OUTER_BOUND('',#2561,.F.);
+#2564=CARTESIAN_POINT('',(1.8036E1,-6.65E-1,-8.601382727273E0));
+#2565=DIRECTION('',(-7.071067811865E-1,0.E0,7.071067811865E-1));
+#2566=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2567=AXIS2_PLACEMENT_3D('',#2564,#2565,#2566);
+#2568=CYLINDRICAL_SURFACE('',#2567,1.E-1);
+#2569=ORIENTED_EDGE('',*,*,#2324,.T.);
+#2571=ORIENTED_EDGE('',*,*,#2570,.T.);
+#2573=ORIENTED_EDGE('',*,*,#2572,.F.);
+#2574=ORIENTED_EDGE('',*,*,#2556,.T.);
+#2575=EDGE_LOOP('',(#2569,#2571,#2573,#2574));
+#2576=FACE_OUTER_BOUND('',#2575,.F.);
+#2578=CARTESIAN_POINT('',(4.601057995356E0,-6.65E-1,4.833559277371E0));
+#2579=DIRECTION('',(9.238795325113E-1,0.E0,-3.826834323651E-1));
+#2580=DIRECTION('',(3.793479438743E-1,-1.317426786372E-1,9.158269509596E-1));
+#2581=AXIS2_PLACEMENT_3D('',#2578,#2579,#2580);
+#2582=SPHERICAL_SURFACE('',#2581,1.E-1);
+#2584=ORIENTED_EDGE('',*,*,#2583,.F.);
+#2585=ORIENTED_EDGE('',*,*,#2570,.F.);
+#2586=ORIENTED_EDGE('',*,*,#2344,.F.);
+#2587=EDGE_LOOP('',(#2584,#2585,#2586));
+#2588=FACE_OUTER_BOUND('',#2587,.F.);
+#2590=CARTESIAN_POINT('',(4.759994499642E0,2.46004E0,5.217265941575E0));
+#2591=DIRECTION('',(-5.041574044985E-2,-9.912839485362E-1,-1.217143643511E-1));
+#2592=DIRECTION('',(7.018361144662E-1,-1.218693434051E-1,7.018361144662E-1));
+#2593=AXIS2_PLACEMENT_3D('',#2590,#2591,#2592);
+#2594=CYLINDRICAL_SURFACE('',#2593,1.E-1);
+#2595=ORIENTED_EDGE('',*,*,#2362,.F.);
+#2596=ORIENTED_EDGE('',*,*,#2413,.F.);
+#2598=ORIENTED_EDGE('',*,*,#2597,.T.);
+#2599=ORIENTED_EDGE('',*,*,#2583,.T.);
+#2600=EDGE_LOOP('',(#2595,#2596,#2598,#2599));
+#2601=FACE_OUTER_BOUND('',#2600,.F.);
+#2603=CARTESIAN_POINT('',(4.67E0,-1.3E-1,5.E0));
+#2604=DIRECTION('',(7.018361144662E-1,-1.218693434051E-1,7.018361144662E-1));
+#2605=DIRECTION('',(7.071067811865E-1,0.E0,-7.071067811865E-1));
+#2606=AXIS2_PLACEMENT_3D('',#2603,#2604,#2605);
+#2607=PLANE('',#2606);
+#2609=ORIENTED_EDGE('',*,*,#2608,.T.);
+#2610=ORIENTED_EDGE('',*,*,#2572,.T.);
+#2611=ORIENTED_EDGE('',*,*,#2597,.F.);
+#2612=ORIENTED_EDGE('',*,*,#2425,.F.);
+#2613=EDGE_LOOP('',(#2609,#2610,#2611,#2612));
+#2614=FACE_OUTER_BOUND('',#2613,.F.);
+#2616=CARTESIAN_POINT('',(5.217265941575E0,2.46004E0,4.759994499642E0));
+#2617=DIRECTION('',(-1.217143643511E-1,-9.912839485362E-1,-5.041574044985E-2));
+#2618=DIRECTION('',(9.925461516413E-1,-1.218693434051E-1,0.E0));
+#2619=AXIS2_PLACEMENT_3D('',#2616,#2617,#2618);
+#2620=CYLINDRICAL_SURFACE('',#2619,1.E-1);
+#2621=ORIENTED_EDGE('',*,*,#2494,.T.);
+#2622=ORIENTED_EDGE('',*,*,#2558,.T.);
+#2623=ORIENTED_EDGE('',*,*,#2608,.F.);
+#2624=ORIENTED_EDGE('',*,*,#2441,.T.);
+#2625=EDGE_LOOP('',(#2621,#2622,#2623,#2624));
+#2626=FACE_OUTER_BOUND('',#2625,.F.);
+#2628=CARTESIAN_POINT('',(-4.601057995356E0,5.35E-1,-4.833559277371E0));
+#2629=DIRECTION('',(-5.295916689784E-1,-6.626200482157E-1,-5.295916689784E-1));
+#2630=DIRECTION('',(-4.685431294435E-1,7.489557207890E-1,-4.685431294435E-1));
+#2631=AXIS2_PLACEMENT_3D('',#2628,#2629,#2630);
+#2632=SPHERICAL_SURFACE('',#2631,1.E-1);
+#2633=ORIENTED_EDGE('',*,*,#1596,.F.);
+#2634=ORIENTED_EDGE('',*,*,#1567,.F.);
+#2635=ORIENTED_EDGE('',*,*,#1537,.F.);
+#2636=EDGE_LOOP('',(#2633,#2634,#2635));
+#2637=FACE_OUTER_BOUND('',#2636,.F.);
+#2639=CLOSED_SHELL('',(#1488,#1503,#1516,#1526,#1541,#1556,#1571,#1586,#1600,
+#1613,#1627,#1642,#1655,#1668,#1682,#1697,#1710,#1725,#1739,#1754,#1768,#1783,
+#1796,#1811,#1825,#1837,#1851,#1865,#1880,#1895,#1909,#1920,#1933,#1947,#1962,
+#1977,#1992,#2006,#2018,#2030,#2042,#2055,#2070,#2084,#2099,#2113,#2128,#2143,
+#2156,#2170,#2184,#2196,#2210,#2223,#2237,#2250,#2264,#2276,#2290,#2302,#2316,
+#2336,#2351,#2366,#2379,#2390,#2403,#2417,#2431,#2445,#2459,#2472,#2486,#2500,
+#2514,#2526,#2539,#2550,#2563,#2577,#2589,#2602,#2615,#2627,#2638));
+#2640=MANIFOLD_SOLID_BREP('',#2639);
+#2641=FILL_AREA_STYLE_COLOUR('',#6);
+#2642=FILL_AREA_STYLE('',(#2641));
+#2643=SURFACE_STYLE_FILL_AREA(#2642);
+#2644=SURFACE_SIDE_STYLE('',(#2643));
+#2645=SURFACE_STYLE_USAGE(.BOTH.,#2644);
+#2646=PRESENTATION_STYLE_ASSIGNMENT((#2645));
+#27=STYLED_ITEM('',(#2646),#2640);
+#2649=PLANE_ANGLE_MEASURE_WITH_UNIT(PLANE_ANGLE_MEASURE(1.745329251994E-2),
+#2648);
+#2650=(CONVERSION_BASED_UNIT('DEGREE',#2649)NAMED_UNIT(*)PLANE_ANGLE_UNIT());
+#2652=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.421086800827E-3),#2647,
+'distance_accuracy_value',
+'Maximum model space distance between geometric entities at asserted connectivities');
+#2654=CARTESIAN_POINT('',(0.E0,0.E0,0.E0));
+#2655=DIRECTION('',(0.E0,0.E0,1.E0));
+#2656=DIRECTION('',(1.E0,0.E0,0.E0));
+#2659=APPLICATION_CONTEXT('automotive_design');
+#2660=APPLICATION_PROTOCOL_DEFINITION('international standard',
+'automotive_design',2001,#2659);
+#2661=PRODUCT_DEFINITION_CONTEXT('part definition',#2659,'design');
+#2662=PRODUCT_CONTEXT('',#2659,'mechanical');
+#2663=PRODUCT('BODY-QFP','BODY-QFP','NOT SPECIFIED',(#2662));
+#2664=PRODUCT_DEFINITION_FORMATION('139','LAST_VERSION',#2663);
+#2672=DERIVED_UNIT_ELEMENT(#2671,2.E0);
+#2673=DERIVED_UNIT((#2672));
+#2674=MEASURE_REPRESENTATION_ITEM('surface area measure',AREA_MEASURE(
+2.459879841527E2),#2673);
+#2679=DERIVED_UNIT_ELEMENT(#2678,3.E0);
+#2680=DERIVED_UNIT((#2679));
+#2681=MEASURE_REPRESENTATION_ITEM('volume measure',VOLUME_MEASURE(
+1.376256164218E2),#2680);
+#2685=CARTESIAN_POINT('centre point',(3.067401223615E-4,-6.504815086187E-2,
+3.067415073299E-4));
+#2690=DERIVED_UNIT_ELEMENT(#2689,2.E0);
+#2691=DERIVED_UNIT((#2690));
+#2692=MEASURE_REPRESENTATION_ITEM('surface area measure',AREA_MEASURE(
+2.459879841527E2),#2691);
+#2697=DERIVED_UNIT_ELEMENT(#2696,3.E0);
+#2698=DERIVED_UNIT((#2697));
+#2699=MEASURE_REPRESENTATION_ITEM('volume measure',VOLUME_MEASURE(
+1.376256164218E2),#2698);
+#2703=CARTESIAN_POINT('centre point',(3.067401223615E-4,-6.504815086187E-2,
+3.067415073299E-4));
+#2709=GENERAL_PROPERTY('','BODY_Z','user defined attribute');
+#2710=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#2709,#2708);
+#2711=VALUE_REPRESENTATION_ITEM('BODY_Z',NUMERIC_MEASURE(1.4E0));
+#2714=DESCRIPTIVE_REPRESENTATION_ITEM('attribute description','Real Number');
+#2723=CARTESIAN_POINT('centre point',(3.067401223615E-4,-3.067415073299E-4,
+7.999518491381E-1));
+#2727=CARTESIAN_POINT('',(0.E0,0.E0,8.65E-1));
+#2728=DIRECTION('',(0.E0,-1.E0,0.E0));
+#2729=DIRECTION('',(1.E0,0.E0,0.E0));
+#2730=AXIS2_PLACEMENT_3D('',#2727,#2728,#2729);
+#2731=ITEM_DEFINED_TRANSFORMATION('','',#2657,#2730);
+#2732=(REPRESENTATION_RELATIONSHIP('','',#2658,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#2731)SHAPE_REPRESENTATION_RELATIONSHIP());
+#2733=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#2732,#2722);
+#2735=DIRECTION('',(0.E0,0.E0,-1.E0));
+#2736=VECTOR('',#2735,2.842615042685E-1);
+#2737=CARTESIAN_POINT('',(-1.1E-1,4.85E-1,-1.157384957315E-1));
+#2738=LINE('',#2737,#2736);
+#2739=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2740=PRESENTATION_STYLE_ASSIGNMENT((#2739));
+#2741=STYLED_ITEM('',(#2740),#2738);
+#2742=DIRECTION('',(0.E0,1.E0,0.E0));
+#2743=VECTOR('',#2742,1.3E-1);
+#2744=CARTESIAN_POINT('',(-1.1E-1,4.85E-1,-4.E-1));
+#2745=LINE('',#2744,#2743);
+#2746=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2747=PRESENTATION_STYLE_ASSIGNMENT((#2746));
+#2748=STYLED_ITEM('',(#2747),#2745);
+#2749=DIRECTION('',(0.E0,0.E0,1.E0));
+#2750=VECTOR('',#2749,2.842615042685E-1);
+#2751=CARTESIAN_POINT('',(-1.1E-1,6.15E-1,-4.E-1));
+#2752=LINE('',#2751,#2750);
+#2753=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2754=PRESENTATION_STYLE_ASSIGNMENT((#2753));
+#2755=STYLED_ITEM('',(#2754),#2752);
+#2756=DIRECTION('',(0.E0,-8.715574274766E-2,9.961946980917E-1));
+#2757=VECTOR('',#2756,4.086015765487E-1);
+#2758=CARTESIAN_POINT('',(-1.1E-1,-8.488271535611E-2,2.042835223674E-1));
+#2759=LINE('',#2758,#2757);
+#2760=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2761=PRESENTATION_STYLE_ASSIGNMENT((#2760));
+#2762=STYLED_ITEM('',(#2761),#2759);
+#2763=DIRECTION('',(0.E0,-9.961946980917E-1,-8.715574274766E-2));
+#2764=VECTOR('',#2763,1.3E-1);
+#2765=CARTESIAN_POINT('',(-1.1E-1,-1.204946892481E-1,6.113302465572E-1));
+#2766=LINE('',#2765,#2764);
+#2767=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2768=PRESENTATION_STYLE_ASSIGNMENT((#2767));
+#2769=STYLED_ITEM('',(#2768),#2766);
+#2770=DIRECTION('',(0.E0,8.715574274766E-2,-9.961946980917E-1));
+#2771=VECTOR('',#2770,4.086015765487E-1);
+#2772=CARTESIAN_POINT('',(-1.1E-1,-2.5E-1,6.E-1));
+#2773=LINE('',#2772,#2771);
+#2774=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2775=PRESENTATION_STYLE_ASSIGNMENT((#2774));
+#2776=STYLED_ITEM('',(#2775),#2773);
+#2777=DIRECTION('',(0.E0,9.961946980917E-1,-8.715574274766E-2));
+#2778=VECTOR('',#2777,4.371257001666E-1);
+#2779=CARTESIAN_POINT('',(1.1E-1,-2.348984548577E-2,2.055095187981E-3));
+#2780=LINE('',#2779,#2778);
+#2781=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2782=PRESENTATION_STYLE_ASSIGNMENT((#2781));
+#2783=STYLED_ITEM('',(#2782),#2780);
+#2784=DIRECTION('',(0.E0,-9.961946980917E-1,8.715574274766E-2));
+#2785=VECTOR('',#2784,4.371257001666E-1);
+#2786=CARTESIAN_POINT('',(-1.1E-1,4.119724594198E-1,-3.604291988413E-2));
+#2787=LINE('',#2786,#2785);
+#2788=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2789=PRESENTATION_STYLE_ASSIGNMENT((#2788));
+#2790=STYLED_ITEM('',(#2789),#2787);
+#2791=DIRECTION('',(0.E0,0.E0,1.E0));
+#2792=VECTOR('',#2791,2.842615042685E-1);
+#2793=CARTESIAN_POINT('',(1.1E-1,6.15E-1,-4.E-1));
+#2794=LINE('',#2793,#2792);
+#2795=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2796=PRESENTATION_STYLE_ASSIGNMENT((#2795));
+#2797=STYLED_ITEM('',(#2796),#2794);
+#2798=DIRECTION('',(0.E0,1.E0,0.E0));
+#2799=VECTOR('',#2798,1.3E-1);
+#2800=CARTESIAN_POINT('',(1.1E-1,4.85E-1,-4.E-1));
+#2801=LINE('',#2800,#2799);
+#2802=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2803=PRESENTATION_STYLE_ASSIGNMENT((#2802));
+#2804=STYLED_ITEM('',(#2803),#2801);
+#2805=DIRECTION('',(0.E0,0.E0,-1.E0));
+#2806=VECTOR('',#2805,2.842615042685E-1);
+#2807=CARTESIAN_POINT('',(1.1E-1,4.85E-1,-1.157384957315E-1));
+#2808=LINE('',#2807,#2806);
+#2809=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2810=PRESENTATION_STYLE_ASSIGNMENT((#2809));
+#2811=STYLED_ITEM('',(#2810),#2808);
+#2812=DIRECTION('',(0.E0,8.715574274766E-2,-9.961946980917E-1));
+#2813=VECTOR('',#2812,4.086015765487E-1);
+#2814=CARTESIAN_POINT('',(1.1E-1,-2.5E-1,6.E-1));
+#2815=LINE('',#2814,#2813);
+#2816=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2817=PRESENTATION_STYLE_ASSIGNMENT((#2816));
+#2818=STYLED_ITEM('',(#2817),#2815);
+#2819=DIRECTION('',(0.E0,-9.961946980917E-1,-8.715574274766E-2));
+#2820=VECTOR('',#2819,1.3E-1);
+#2821=CARTESIAN_POINT('',(1.1E-1,-1.204946892481E-1,6.113302465572E-1));
+#2822=LINE('',#2821,#2820);
+#2823=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2824=PRESENTATION_STYLE_ASSIGNMENT((#2823));
+#2825=STYLED_ITEM('',(#2824),#2822);
+#2826=DIRECTION('',(0.E0,-8.715574274766E-2,9.961946980917E-1));
+#2827=VECTOR('',#2826,4.086015765487E-1);
+#2828=CARTESIAN_POINT('',(1.1E-1,-8.488271535611E-2,2.042835223674E-1));
+#2829=LINE('',#2828,#2827);
+#2830=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2831=PRESENTATION_STYLE_ASSIGNMENT((#2830));
+#2832=STYLED_ITEM('',(#2831),#2829);
+#2833=DIRECTION('',(0.E0,9.961946980917E-1,-8.715574274766E-2));
+#2834=VECTOR('',#2833,4.371257001666E-1);
+#2835=CARTESIAN_POINT('',(-1.1E-1,-1.215959892858E-2,1.315604059399E-1));
+#2836=LINE('',#2835,#2834);
+#2837=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2838=PRESENTATION_STYLE_ASSIGNMENT((#2837));
+#2839=STYLED_ITEM('',(#2838),#2836);
+#2840=DIRECTION('',(0.E0,-9.961946980917E-1,8.715574274766E-2));
+#2841=VECTOR('',#2840,4.371257001666E-1);
+#2842=CARTESIAN_POINT('',(1.1E-1,4.233027059770E-1,9.346239086780E-2));
+#2843=LINE('',#2842,#2841);
+#2844=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2845=PRESENTATION_STYLE_ASSIGNMENT((#2844));
+#2846=STYLED_ITEM('',(#2845),#2843);
+#2847=DIRECTION('',(1.E0,0.E0,0.E0));
+#2848=VECTOR('',#2847,2.2E-1);
+#2849=CARTESIAN_POINT('',(-1.1E-1,4.233027059770E-1,9.346239086780E-2));
+#2850=LINE('',#2849,#2848);
+#2851=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2852=PRESENTATION_STYLE_ASSIGNMENT((#2851));
+#2853=STYLED_ITEM('',(#2852),#2850);
+#2854=CARTESIAN_POINT('',(-1.1E-1,4.05E-1,-1.157384957315E-1));
+#2855=DIRECTION('',(-1.E0,0.E0,0.E0));
+#2856=DIRECTION('',(0.E0,8.715574274766E-2,9.961946980917E-1));
+#2857=AXIS2_PLACEMENT_3D('',#2854,#2855,#2856);
+#2859=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2860=PRESENTATION_STYLE_ASSIGNMENT((#2859));
+#2861=STYLED_ITEM('',(#2860),#2858);
+#2862=DIRECTION('',(1.E0,0.E0,0.E0));
+#2863=VECTOR('',#2862,2.2E-1);
+#2864=CARTESIAN_POINT('',(-1.1E-1,6.15E-1,-1.157384957315E-1));
+#2865=LINE('',#2864,#2863);
+#2866=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2867=PRESENTATION_STYLE_ASSIGNMENT((#2866));
+#2868=STYLED_ITEM('',(#2867),#2865);
+#2869=CARTESIAN_POINT('',(1.1E-1,4.05E-1,-1.157384957315E-1));
+#2870=DIRECTION('',(-1.E0,0.E0,0.E0));
+#2871=DIRECTION('',(0.E0,8.715574274766E-2,9.961946980917E-1));
+#2872=AXIS2_PLACEMENT_3D('',#2869,#2870,#2871);
+#2874=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2875=PRESENTATION_STYLE_ASSIGNMENT((#2874));
+#2876=STYLED_ITEM('',(#2875),#2873);
+#2877=DIRECTION('',(1.E0,0.E0,0.E0));
+#2878=VECTOR('',#2877,2.2E-1);
+#2879=CARTESIAN_POINT('',(-1.1E-1,6.15E-1,-4.E-1));
+#2880=LINE('',#2879,#2878);
+#2881=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2882=PRESENTATION_STYLE_ASSIGNMENT((#2881));
+#2883=STYLED_ITEM('',(#2882),#2880);
+#2884=DIRECTION('',(1.E0,0.E0,0.E0));
+#2885=VECTOR('',#2884,2.2E-1);
+#2886=CARTESIAN_POINT('',(-1.1E-1,4.85E-1,-4.E-1));
+#2887=LINE('',#2886,#2885);
+#2888=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2889=PRESENTATION_STYLE_ASSIGNMENT((#2888));
+#2890=STYLED_ITEM('',(#2889),#2887);
+#2891=DIRECTION('',(1.E0,0.E0,0.E0));
+#2892=VECTOR('',#2891,2.2E-1);
+#2893=CARTESIAN_POINT('',(-1.1E-1,4.85E-1,-1.157384957315E-1));
+#2894=LINE('',#2893,#2892);
+#2895=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2896=PRESENTATION_STYLE_ASSIGNMENT((#2895));
+#2897=STYLED_ITEM('',(#2896),#2894);
+#2898=CARTESIAN_POINT('',(-1.1E-1,4.05E-1,-1.157384957315E-1));
+#2899=DIRECTION('',(1.E0,0.E0,0.E0));
+#2900=DIRECTION('',(0.E0,1.E0,0.E0));
+#2901=AXIS2_PLACEMENT_3D('',#2898,#2899,#2900);
+#2903=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2904=PRESENTATION_STYLE_ASSIGNMENT((#2903));
+#2905=STYLED_ITEM('',(#2904),#2902);
+#2906=DIRECTION('',(1.E0,0.E0,0.E0));
+#2907=VECTOR('',#2906,2.2E-1);
+#2908=CARTESIAN_POINT('',(-1.1E-1,4.119724594198E-1,-3.604291988413E-2));
+#2909=LINE('',#2908,#2907);
+#2910=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2911=PRESENTATION_STYLE_ASSIGNMENT((#2910));
+#2912=STYLED_ITEM('',(#2911),#2909);
+#2913=CARTESIAN_POINT('',(1.1E-1,4.05E-1,-1.157384957315E-1));
+#2914=DIRECTION('',(1.E0,0.E0,0.E0));
+#2915=DIRECTION('',(0.E0,1.E0,0.E0));
+#2916=AXIS2_PLACEMENT_3D('',#2913,#2914,#2915);
+#2918=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2919=PRESENTATION_STYLE_ASSIGNMENT((#2918));
+#2920=STYLED_ITEM('',(#2919),#2917);
+#2921=DIRECTION('',(1.E0,0.E0,0.E0));
+#2922=VECTOR('',#2921,2.2E-1);
+#2923=CARTESIAN_POINT('',(-1.1E-1,-8.488271535611E-2,2.042835223674E-1));
+#2924=LINE('',#2923,#2922);
+#2925=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2926=PRESENTATION_STYLE_ASSIGNMENT((#2925));
+#2927=STYLED_ITEM('',(#2926),#2924);
+#2928=CARTESIAN_POINT('',(-1.1E-1,-5.187139508766E-3,2.112559817872E-1));
+#2929=DIRECTION('',(1.E0,0.E0,0.E0));
+#2930=DIRECTION('',(0.E0,-9.961946980917E-1,-8.715574274766E-2));
+#2931=AXIS2_PLACEMENT_3D('',#2928,#2929,#2930);
+#2933=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2934=PRESENTATION_STYLE_ASSIGNMENT((#2933));
+#2935=STYLED_ITEM('',(#2934),#2932);
+#2936=DIRECTION('',(1.E0,0.E0,0.E0));
+#2937=VECTOR('',#2936,2.2E-1);
+#2938=CARTESIAN_POINT('',(-1.1E-1,-1.215959892858E-2,1.315604059399E-1));
+#2939=LINE('',#2938,#2937);
+#2940=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2941=PRESENTATION_STYLE_ASSIGNMENT((#2940));
+#2942=STYLED_ITEM('',(#2941),#2939);
+#2943=CARTESIAN_POINT('',(1.1E-1,-5.187139508766E-3,2.112559817872E-1));
+#2944=DIRECTION('',(1.E0,0.E0,0.E0));
+#2945=DIRECTION('',(0.E0,-9.961946980917E-1,-8.715574274766E-2));
+#2946=AXIS2_PLACEMENT_3D('',#2943,#2944,#2945);
+#2948=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2949=PRESENTATION_STYLE_ASSIGNMENT((#2948));
+#2950=STYLED_ITEM('',(#2949),#2947);
+#2951=DIRECTION('',(1.E0,0.E0,0.E0));
+#2952=VECTOR('',#2951,2.2E-1);
+#2953=CARTESIAN_POINT('',(-1.1E-1,-1.204946892481E-1,6.113302465572E-1));
+#2954=LINE('',#2953,#2952);
+#2955=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2956=PRESENTATION_STYLE_ASSIGNMENT((#2955));
+#2957=STYLED_ITEM('',(#2956),#2954);
+#2958=DIRECTION('',(1.E0,0.E0,0.E0));
+#2959=VECTOR('',#2958,2.2E-1);
+#2960=CARTESIAN_POINT('',(-1.1E-1,-2.5E-1,6.E-1));
+#2961=LINE('',#2960,#2959);
+#2962=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2963=PRESENTATION_STYLE_ASSIGNMENT((#2962));
+#2964=STYLED_ITEM('',(#2963),#2961);
+#2965=DIRECTION('',(1.E0,0.E0,0.E0));
+#2966=VECTOR('',#2965,2.2E-1);
+#2967=CARTESIAN_POINT('',(-1.1E-1,-2.348984548577E-2,2.055095187981E-3));
+#2968=LINE('',#2967,#2966);
+#2969=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2970=PRESENTATION_STYLE_ASSIGNMENT((#2969));
+#2971=STYLED_ITEM('',(#2970),#2968);
+#2972=CARTESIAN_POINT('',(-1.1E-1,-5.187139508766E-3,2.112559817872E-1));
+#2973=DIRECTION('',(-1.E0,0.E0,0.E0));
+#2974=DIRECTION('',(0.E0,-8.715574274766E-2,-9.961946980917E-1));
+#2975=AXIS2_PLACEMENT_3D('',#2972,#2973,#2974);
+#2977=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2978=PRESENTATION_STYLE_ASSIGNMENT((#2977));
+#2979=STYLED_ITEM('',(#2978),#2976);
+#2980=DIRECTION('',(1.E0,0.E0,0.E0));
+#2981=VECTOR('',#2980,2.2E-1);
+#2982=CARTESIAN_POINT('',(-1.1E-1,-2.143880261080E-1,1.929532758102E-1));
+#2983=LINE('',#2982,#2981);
+#2984=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2985=PRESENTATION_STYLE_ASSIGNMENT((#2984));
+#2986=STYLED_ITEM('',(#2985),#2983);
+#2987=CARTESIAN_POINT('',(1.1E-1,-5.187139508766E-3,2.112559817872E-1));
+#2988=DIRECTION('',(-1.E0,0.E0,0.E0));
+#2989=DIRECTION('',(0.E0,-8.715574274766E-2,-9.961946980917E-1));
+#2990=AXIS2_PLACEMENT_3D('',#2987,#2988,#2989);
+#2992=CURVE_STYLE('',#33,POSITIVE_LENGTH_MEASURE(2.E-2),#26);
+#2993=PRESENTATION_STYLE_ASSIGNMENT((#2992));
+#2994=STYLED_ITEM('',(#2993),#2991);
+#2995=CARTESIAN_POINT('',(-1.1E-1,-1.204946892481E-1,6.113302465572E-1));
+#2996=CARTESIAN_POINT('',(-1.1E-1,-2.5E-1,6.E-1));
+#2997=VERTEX_POINT('',#2995);
+#2998=VERTEX_POINT('',#2996);
+#2999=CARTESIAN_POINT('',(1.1E-1,-1.204946892481E-1,6.113302465572E-1));
+#3000=CARTESIAN_POINT('',(1.1E-1,-2.5E-1,6.E-1));
+#3001=VERTEX_POINT('',#2999);
+#3002=VERTEX_POINT('',#3000);
+#3003=CARTESIAN_POINT('',(-1.1E-1,4.85E-1,-4.E-1));
+#3004=CARTESIAN_POINT('',(-1.1E-1,6.15E-1,-4.E-1));
+#3005=VERTEX_POINT('',#3003);
+#3006=VERTEX_POINT('',#3004);
+#3007=CARTESIAN_POINT('',(1.1E-1,4.85E-1,-4.E-1));
+#3008=CARTESIAN_POINT('',(1.1E-1,6.15E-1,-4.E-1));
+#3009=VERTEX_POINT('',#3007);
+#3010=VERTEX_POINT('',#3008);
+#3011=CARTESIAN_POINT('',(-1.1E-1,4.85E-1,-1.157384957315E-1));
+#3012=CARTESIAN_POINT('',(1.1E-1,4.85E-1,-1.157384957315E-1));
+#3013=VERTEX_POINT('',#3011);
+#3014=VERTEX_POINT('',#3012);
+#3015=CARTESIAN_POINT('',(-1.1E-1,4.119724594198E-1,-3.604291988413E-2));
+#3016=CARTESIAN_POINT('',(1.1E-1,4.119724594198E-1,-3.604291988413E-2));
+#3017=VERTEX_POINT('',#3015);
+#3018=VERTEX_POINT('',#3016);
+#3019=CARTESIAN_POINT('',(-1.1E-1,4.233027059770E-1,9.346239086780E-2));
+#3020=CARTESIAN_POINT('',(1.1E-1,4.233027059770E-1,9.346239086780E-2));
+#3021=VERTEX_POINT('',#3019);
+#3022=VERTEX_POINT('',#3020);
+#3023=CARTESIAN_POINT('',(-1.1E-1,6.15E-1,-1.157384957315E-1));
+#3024=CARTESIAN_POINT('',(1.1E-1,6.15E-1,-1.157384957315E-1));
+#3025=VERTEX_POINT('',#3023);
+#3026=VERTEX_POINT('',#3024);
+#3027=CARTESIAN_POINT('',(-1.1E-1,-8.488271535611E-2,2.042835223674E-1));
+#3028=CARTESIAN_POINT('',(1.1E-1,-8.488271535611E-2,2.042835223674E-1));
+#3029=VERTEX_POINT('',#3027);
+#3030=VERTEX_POINT('',#3028);
+#3031=CARTESIAN_POINT('',(-1.1E-1,-1.215959892858E-2,1.315604059399E-1));
+#3032=CARTESIAN_POINT('',(1.1E-1,-1.215959892858E-2,1.315604059399E-1));
+#3033=VERTEX_POINT('',#3031);
+#3034=VERTEX_POINT('',#3032);
+#3035=CARTESIAN_POINT('',(-1.1E-1,-2.348984548577E-2,2.055095187981E-3));
+#3036=CARTESIAN_POINT('',(1.1E-1,-2.348984548577E-2,2.055095187981E-3));
+#3037=VERTEX_POINT('',#3035);
+#3038=VERTEX_POINT('',#3036);
+#3039=CARTESIAN_POINT('',(-1.1E-1,-2.143880261080E-1,1.929532758102E-1));
+#3040=CARTESIAN_POINT('',(1.1E-1,-2.143880261080E-1,1.929532758102E-1));
+#3041=VERTEX_POINT('',#3039);
+#3042=VERTEX_POINT('',#3040);
+#3043=CARTESIAN_POINT('',(-1.1E-1,0.E0,0.E0));
+#3044=DIRECTION('',(1.E0,0.E0,0.E0));
+#3045=DIRECTION('',(0.E0,0.E0,-1.E0));
+#3046=AXIS2_PLACEMENT_3D('',#3043,#3044,#3045);
+#3047=PLANE('',#3046);
+#3049=ORIENTED_EDGE('',*,*,#3048,.F.);
+#3051=ORIENTED_EDGE('',*,*,#3050,.F.);
+#3053=ORIENTED_EDGE('',*,*,#3052,.T.);
+#3055=ORIENTED_EDGE('',*,*,#3054,.T.);
+#3057=ORIENTED_EDGE('',*,*,#3056,.T.);
+#3059=ORIENTED_EDGE('',*,*,#3058,.F.);
+#3061=ORIENTED_EDGE('',*,*,#3060,.F.);
+#3063=ORIENTED_EDGE('',*,*,#3062,.F.);
+#3065=ORIENTED_EDGE('',*,*,#3064,.T.);
+#3067=ORIENTED_EDGE('',*,*,#3066,.T.);
+#3069=ORIENTED_EDGE('',*,*,#3068,.T.);
+#3071=ORIENTED_EDGE('',*,*,#3070,.F.);
+#3072=EDGE_LOOP('',(#3049,#3051,#3053,#3055,#3057,#3059,#3061,#3063,#3065,#3067,
+#3069,#3071));
+#3073=FACE_OUTER_BOUND('',#3072,.F.);
+#3075=CARTESIAN_POINT('',(-1.1E-1,-1.990302322732E-1,1.741288902283E-2));
+#3076=DIRECTION('',(0.E0,-8.715574274766E-2,-9.961946980917E-1));
+#3077=DIRECTION('',(0.E0,9.961946980917E-1,-8.715574274766E-2));
+#3078=AXIS2_PLACEMENT_3D('',#3075,#3076,#3077);
+#3079=PLANE('',#3078);
+#3081=ORIENTED_EDGE('',*,*,#3080,.T.);
+#3083=ORIENTED_EDGE('',*,*,#3082,.F.);
+#3084=ORIENTED_EDGE('',*,*,#3048,.T.);
+#3086=ORIENTED_EDGE('',*,*,#3085,.T.);
+#3087=EDGE_LOOP('',(#3081,#3083,#3084,#3086));
+#3088=FACE_OUTER_BOUND('',#3087,.F.);
+#3090=CARTESIAN_POINT('',(1.1E-1,0.E0,0.E0));
+#3091=DIRECTION('',(1.E0,0.E0,0.E0));
+#3092=DIRECTION('',(0.E0,0.E0,-1.E0));
+#3093=AXIS2_PLACEMENT_3D('',#3090,#3091,#3092);
+#3094=PLANE('',#3093);
+#3096=ORIENTED_EDGE('',*,*,#3095,.F.);
+#3098=ORIENTED_EDGE('',*,*,#3097,.T.);
+#3100=ORIENTED_EDGE('',*,*,#3099,.F.);
+#3102=ORIENTED_EDGE('',*,*,#3101,.F.);
+#3104=ORIENTED_EDGE('',*,*,#3103,.F.);
+#3106=ORIENTED_EDGE('',*,*,#3105,.T.);
+#3107=ORIENTED_EDGE('',*,*,#3080,.F.);
+#3109=ORIENTED_EDGE('',*,*,#3108,.T.);
+#3111=ORIENTED_EDGE('',*,*,#3110,.F.);
+#3113=ORIENTED_EDGE('',*,*,#3112,.F.);
+#3115=ORIENTED_EDGE('',*,*,#3114,.F.);
+#3117=ORIENTED_EDGE('',*,*,#3116,.T.);
+#3118=EDGE_LOOP('',(#3096,#3098,#3100,#3102,#3104,#3106,#3107,#3109,#3111,#3113,
+#3115,#3117));
+#3119=FACE_OUTER_BOUND('',#3118,.F.);
+#3121=CARTESIAN_POINT('',(-1.1E-1,1.133024655720E-2,1.295053107519E-1));
+#3122=DIRECTION('',(0.E0,8.715574274766E-2,9.961946980917E-1));
+#3123=DIRECTION('',(0.E0,-9.961946980917E-1,8.715574274766E-2));
+#3124=AXIS2_PLACEMENT_3D('',#3121,#3122,#3123);
+#3125=PLANE('',#3124);
+#3126=ORIENTED_EDGE('',*,*,#3060,.T.);
+#3128=ORIENTED_EDGE('',*,*,#3127,.T.);
+#3129=ORIENTED_EDGE('',*,*,#3095,.T.);
+#3131=ORIENTED_EDGE('',*,*,#3130,.F.);
+#3132=EDGE_LOOP('',(#3126,#3128,#3129,#3131));
+#3133=FACE_OUTER_BOUND('',#3132,.F.);
+#3135=CARTESIAN_POINT('',(-1.1E-1,4.05E-1,-1.157384957315E-1));
+#3136=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3137=DIRECTION('',(0.E0,8.715574274766E-2,9.961946980917E-1));
+#3138=AXIS2_PLACEMENT_3D('',#3135,#3136,#3137);
+#3139=CYLINDRICAL_SURFACE('',#3138,2.1E-1);
+#3140=ORIENTED_EDGE('',*,*,#3127,.F.);
+#3141=ORIENTED_EDGE('',*,*,#3058,.T.);
+#3143=ORIENTED_EDGE('',*,*,#3142,.T.);
+#3144=ORIENTED_EDGE('',*,*,#3097,.F.);
+#3145=EDGE_LOOP('',(#3140,#3141,#3143,#3144));
+#3146=FACE_OUTER_BOUND('',#3145,.F.);
+#3148=CARTESIAN_POINT('',(-1.1E-1,6.15E-1,-4.E-1));
+#3149=DIRECTION('',(0.E0,1.E0,0.E0));
+#3150=DIRECTION('',(0.E0,0.E0,1.E0));
+#3151=AXIS2_PLACEMENT_3D('',#3148,#3149,#3150);
+#3152=PLANE('',#3151);
+#3153=ORIENTED_EDGE('',*,*,#3056,.F.);
+#3155=ORIENTED_EDGE('',*,*,#3154,.T.);
+#3156=ORIENTED_EDGE('',*,*,#3099,.T.);
+#3157=ORIENTED_EDGE('',*,*,#3142,.F.);
+#3158=EDGE_LOOP('',(#3153,#3155,#3156,#3157));
+#3159=FACE_OUTER_BOUND('',#3158,.F.);
+#3161=CARTESIAN_POINT('',(-1.1E-1,4.85E-1,-4.E-1));
+#3162=DIRECTION('',(0.E0,0.E0,-1.E0));
+#3163=DIRECTION('',(0.E0,1.E0,0.E0));
+#3164=AXIS2_PLACEMENT_3D('',#3161,#3162,#3163);
+#3165=PLANE('',#3164);
+#3166=ORIENTED_EDGE('',*,*,#3054,.F.);
+#3168=ORIENTED_EDGE('',*,*,#3167,.T.);
+#3169=ORIENTED_EDGE('',*,*,#3101,.T.);
+#3170=ORIENTED_EDGE('',*,*,#3154,.F.);
+#3171=EDGE_LOOP('',(#3166,#3168,#3169,#3170));
+#3172=FACE_OUTER_BOUND('',#3171,.F.);
+#3174=CARTESIAN_POINT('',(-1.1E-1,4.85E-1,-4.243200181007E-2));
+#3175=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3176=DIRECTION('',(0.E0,0.E0,-1.E0));
+#3177=AXIS2_PLACEMENT_3D('',#3174,#3175,#3176);
+#3178=PLANE('',#3177);
+#3179=ORIENTED_EDGE('',*,*,#3052,.F.);
+#3181=ORIENTED_EDGE('',*,*,#3180,.T.);
+#3182=ORIENTED_EDGE('',*,*,#3103,.T.);
+#3183=ORIENTED_EDGE('',*,*,#3167,.F.);
+#3184=EDGE_LOOP('',(#3179,#3181,#3182,#3183));
+#3185=FACE_OUTER_BOUND('',#3184,.F.);
+#3187=CARTESIAN_POINT('',(-1.1E-1,4.05E-1,-1.157384957315E-1));
+#3188=DIRECTION('',(1.E0,0.E0,0.E0));
+#3189=DIRECTION('',(0.E0,1.E0,0.E0));
+#3190=AXIS2_PLACEMENT_3D('',#3187,#3188,#3189);
+#3191=CYLINDRICAL_SURFACE('',#3190,8.E-2);
+#3192=ORIENTED_EDGE('',*,*,#3180,.F.);
+#3193=ORIENTED_EDGE('',*,*,#3050,.T.);
+#3194=ORIENTED_EDGE('',*,*,#3082,.T.);
+#3195=ORIENTED_EDGE('',*,*,#3105,.F.);
+#3196=EDGE_LOOP('',(#3192,#3193,#3194,#3195));
+#3197=FACE_OUTER_BOUND('',#3196,.F.);
+#3199=CARTESIAN_POINT('',(-1.1E-1,-5.187139508766E-3,2.112559817872E-1));
+#3200=DIRECTION('',(1.E0,0.E0,0.E0));
+#3201=DIRECTION('',(0.E0,-9.961946980917E-1,-8.715574274766E-2));
+#3202=AXIS2_PLACEMENT_3D('',#3199,#3200,#3201);
+#3203=CYLINDRICAL_SURFACE('',#3202,8.E-2);
+#3205=ORIENTED_EDGE('',*,*,#3204,.F.);
+#3206=ORIENTED_EDGE('',*,*,#3062,.T.);
+#3207=ORIENTED_EDGE('',*,*,#3130,.T.);
+#3208=ORIENTED_EDGE('',*,*,#3116,.F.);
+#3209=EDGE_LOOP('',(#3205,#3206,#3207,#3208));
+#3210=FACE_OUTER_BOUND('',#3209,.F.);
+#3212=CARTESIAN_POINT('',(-1.1E-1,-7.903212722854E-2,1.374109940675E-1));
+#3213=DIRECTION('',(0.E0,9.961946980917E-1,8.715574274766E-2));
+#3214=DIRECTION('',(0.E0,-8.715574274766E-2,9.961946980917E-1));
+#3215=AXIS2_PLACEMENT_3D('',#3212,#3213,#3214);
+#3216=PLANE('',#3215);
+#3217=ORIENTED_EDGE('',*,*,#3064,.F.);
+#3218=ORIENTED_EDGE('',*,*,#3204,.T.);
+#3219=ORIENTED_EDGE('',*,*,#3114,.T.);
+#3221=ORIENTED_EDGE('',*,*,#3220,.F.);
+#3222=EDGE_LOOP('',(#3217,#3218,#3219,#3221));
+#3223=FACE_OUTER_BOUND('',#3222,.F.);
+#3225=CARTESIAN_POINT('',(-1.1E-1,-1.204946892481E-1,6.113302465572E-1));
+#3226=DIRECTION('',(0.E0,-8.715574274766E-2,9.961946980917E-1));
+#3227=DIRECTION('',(0.E0,-9.961946980917E-1,-8.715574274766E-2));
+#3228=AXIS2_PLACEMENT_3D('',#3225,#3226,#3227);
+#3229=PLANE('',#3228);
+#3230=ORIENTED_EDGE('',*,*,#3066,.F.);
+#3231=ORIENTED_EDGE('',*,*,#3220,.T.);
+#3232=ORIENTED_EDGE('',*,*,#3112,.T.);
+#3234=ORIENTED_EDGE('',*,*,#3233,.F.);
+#3235=EDGE_LOOP('',(#3230,#3231,#3232,#3234));
+#3236=FACE_OUTER_BOUND('',#3235,.F.);
+#3238=CARTESIAN_POINT('',(-1.1E-1,-2.5E-1,6.E-1));
+#3239=DIRECTION('',(0.E0,-9.961946980917E-1,-8.715574274766E-2));
+#3240=DIRECTION('',(0.E0,8.715574274766E-2,-9.961946980917E-1));
+#3241=AXIS2_PLACEMENT_3D('',#3238,#3239,#3240);
+#3242=PLANE('',#3241);
+#3243=ORIENTED_EDGE('',*,*,#3068,.F.);
+#3244=ORIENTED_EDGE('',*,*,#3233,.T.);
+#3245=ORIENTED_EDGE('',*,*,#3110,.T.);
+#3247=ORIENTED_EDGE('',*,*,#3246,.F.);
+#3248=EDGE_LOOP('',(#3243,#3244,#3245,#3247));
+#3249=FACE_OUTER_BOUND('',#3248,.F.);
+#3251=CARTESIAN_POINT('',(-1.1E-1,-5.187139508766E-3,2.112559817872E-1));
+#3252=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3253=DIRECTION('',(0.E0,-8.715574274766E-2,-9.961946980917E-1));
+#3254=AXIS2_PLACEMENT_3D('',#3251,#3252,#3253);
+#3255=CYLINDRICAL_SURFACE('',#3254,2.1E-1);
+#3256=ORIENTED_EDGE('',*,*,#3085,.F.);
+#3257=ORIENTED_EDGE('',*,*,#3070,.T.);
+#3258=ORIENTED_EDGE('',*,*,#3246,.T.);
+#3259=ORIENTED_EDGE('',*,*,#3108,.F.);
+#3260=EDGE_LOOP('',(#3256,#3257,#3258,#3259));
+#3261=FACE_OUTER_BOUND('',#3260,.F.);
+#3263=CLOSED_SHELL('',(#3074,#3089,#3120,#3134,#3147,#3160,#3173,#3186,#3198,
+#3211,#3224,#3237,#3250,#3262));
+#3264=MANIFOLD_SOLID_BREP('',#3263);
+#3265=FILL_AREA_STYLE_COLOUR('',#26);
+#3266=FILL_AREA_STYLE('',(#3265));
+#3267=SURFACE_STYLE_FILL_AREA(#3266);
+#3268=SURFACE_SIDE_STYLE('',(#3267));
+#3269=SURFACE_STYLE_USAGE(.BOTH.,#3268);
+#3270=PRESENTATION_STYLE_ASSIGNMENT((#3269));
+#2734=STYLED_ITEM('',(#3270),#3264);
+#3273=PLANE_ANGLE_MEASURE_WITH_UNIT(PLANE_ANGLE_MEASURE(1.745329251994E-2),
+#3272);
+#3274=(CONVERSION_BASED_UNIT('DEGREE',#3273)NAMED_UNIT(*)PLANE_ANGLE_UNIT());
+#3276=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.348802549450E-4),#3271,
+'distance_accuracy_value',
+'Maximum model space distance between geometric entities at asserted connectivities');
+#3278=CARTESIAN_POINT('',(0.E0,0.E0,0.E0));
+#3279=DIRECTION('',(0.E0,0.E0,1.E0));
+#3280=DIRECTION('',(1.E0,0.E0,0.E0));
+#3283=PRODUCT_CONTEXT('',#2659,'mechanical');
+#3284=PRODUCT('LEAD-QFP','LEAD-QFP','NOT SPECIFIED',(#3283));
+#3285=PRODUCT_DEFINITION_FORMATION('76','LAST_VERSION',#3284);
+#3293=DERIVED_UNIT_ELEMENT(#3292,2.E0);
+#3294=DERIVED_UNIT((#3293));
+#3295=MEASURE_REPRESENTATION_ITEM('surface area measure',AREA_MEASURE(
+1.140491163205E0),#3294);
+#3300=DERIVED_UNIT_ELEMENT(#3299,3.E0);
+#3301=DERIVED_UNIT((#3300));
+#3302=MEASURE_REPRESENTATION_ITEM('volume measure',VOLUME_MEASURE(
+4.426018180904E-2),#3301);
+#3306=CARTESIAN_POINT('centre point',(0.E0,1.701625611455E-1,
+8.390581416545E-2));
+#3311=DERIVED_UNIT_ELEMENT(#3310,2.E0);
+#3312=DERIVED_UNIT((#3311));
+#3313=MEASURE_REPRESENTATION_ITEM('surface area measure',AREA_MEASURE(
+1.140491163205E0),#3312);
+#3318=DERIVED_UNIT_ELEMENT(#3317,3.E0);
+#3319=DERIVED_UNIT((#3318));
+#3320=MEASURE_REPRESENTATION_ITEM('volume measure',VOLUME_MEASURE(
+4.426018180904E-2),#3319);
+#3324=CARTESIAN_POINT('centre point',(0.E0,1.701625611455E-1,
+8.390581416545E-2));
+#3331=CARTESIAN_POINT('centre point',(-3.75E0,-5.483905814165E0,
+4.201625611455E-1));
+#3335=CARTESIAN_POINT('',(-3.75E0,-5.4E0,2.5E-1));
+#3336=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3337=DIRECTION('',(1.E0,0.E0,0.E0));
+#3338=AXIS2_PLACEMENT_3D('',#3335,#3336,#3337);
+#3339=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3338);
+#3340=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3339)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3341=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3340,#3330);
+#3344=CARTESIAN_POINT('centre point',(-3.25E0,-5.483905814165E0,
+4.201625611455E-1));
+#3348=CARTESIAN_POINT('',(-3.25E0,-5.4E0,2.5E-1));
+#3349=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3350=DIRECTION('',(1.E0,0.E0,0.E0));
+#3351=AXIS2_PLACEMENT_3D('',#3348,#3349,#3350);
+#3352=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3351);
+#3353=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3352)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3354=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3353,#3343);
+#3357=CARTESIAN_POINT('centre point',(-2.75E0,-5.483905814165E0,
+4.201625611455E-1));
+#3361=CARTESIAN_POINT('',(-2.75E0,-5.4E0,2.5E-1));
+#3362=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3363=DIRECTION('',(1.E0,0.E0,0.E0));
+#3364=AXIS2_PLACEMENT_3D('',#3361,#3362,#3363);
+#3365=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3364);
+#3366=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3365)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3367=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3366,#3356);
+#3370=CARTESIAN_POINT('centre point',(-2.25E0,-5.483905814165E0,
+4.201625611455E-1));
+#3374=CARTESIAN_POINT('',(-2.25E0,-5.4E0,2.5E-1));
+#3375=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3376=DIRECTION('',(1.E0,0.E0,0.E0));
+#3377=AXIS2_PLACEMENT_3D('',#3374,#3375,#3376);
+#3378=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3377);
+#3379=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3378)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3380=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3379,#3369);
+#3383=CARTESIAN_POINT('centre point',(-1.75E0,-5.483905814165E0,
+4.201625611455E-1));
+#3387=CARTESIAN_POINT('',(-1.75E0,-5.4E0,2.5E-1));
+#3388=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3389=DIRECTION('',(1.E0,0.E0,0.E0));
+#3390=AXIS2_PLACEMENT_3D('',#3387,#3388,#3389);
+#3391=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3390);
+#3392=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3391)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3393=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3392,#3382);
+#3396=CARTESIAN_POINT('centre point',(-1.25E0,-5.483905814165E0,
+4.201625611455E-1));
+#3400=CARTESIAN_POINT('',(-1.25E0,-5.4E0,2.5E-1));
+#3401=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3402=DIRECTION('',(1.E0,0.E0,0.E0));
+#3403=AXIS2_PLACEMENT_3D('',#3400,#3401,#3402);
+#3404=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3403);
+#3405=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3404)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3406=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3405,#3395);
+#3409=CARTESIAN_POINT('centre point',(-7.5E-1,-5.483905814165E0,
+4.201625611455E-1));
+#3413=CARTESIAN_POINT('',(-7.5E-1,-5.4E0,2.5E-1));
+#3414=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3415=DIRECTION('',(1.E0,0.E0,0.E0));
+#3416=AXIS2_PLACEMENT_3D('',#3413,#3414,#3415);
+#3417=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3416);
+#3418=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3417)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3419=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3418,#3408);
+#3422=CARTESIAN_POINT('centre point',(-2.5E-1,-5.483905814165E0,
+4.201625611455E-1));
+#3426=CARTESIAN_POINT('',(-2.5E-1,-5.4E0,2.5E-1));
+#3427=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3428=DIRECTION('',(1.E0,0.E0,0.E0));
+#3429=AXIS2_PLACEMENT_3D('',#3426,#3427,#3428);
+#3430=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3429);
+#3431=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3430)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3432=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3431,#3421);
+#3435=CARTESIAN_POINT('centre point',(2.5E-1,-5.483905814165E0,
+4.201625611455E-1));
+#3439=CARTESIAN_POINT('',(2.5E-1,-5.4E0,2.5E-1));
+#3440=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3441=DIRECTION('',(1.E0,0.E0,0.E0));
+#3442=AXIS2_PLACEMENT_3D('',#3439,#3440,#3441);
+#3443=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3442);
+#3444=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3443)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3445=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3444,#3434);
+#3448=CARTESIAN_POINT('centre point',(7.5E-1,-5.483905814165E0,
+4.201625611455E-1));
+#3452=CARTESIAN_POINT('',(7.5E-1,-5.4E0,2.5E-1));
+#3453=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3454=DIRECTION('',(1.E0,0.E0,0.E0));
+#3455=AXIS2_PLACEMENT_3D('',#3452,#3453,#3454);
+#3456=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3455);
+#3457=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3456)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3458=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3457,#3447);
+#3461=CARTESIAN_POINT('centre point',(1.25E0,-5.483905814165E0,
+4.201625611455E-1));
+#3465=CARTESIAN_POINT('',(1.25E0,-5.4E0,2.5E-1));
+#3466=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3467=DIRECTION('',(1.E0,0.E0,0.E0));
+#3468=AXIS2_PLACEMENT_3D('',#3465,#3466,#3467);
+#3469=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3468);
+#3470=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3469)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3471=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3470,#3460);
+#3474=CARTESIAN_POINT('centre point',(1.75E0,-5.483905814165E0,
+4.201625611455E-1));
+#3478=CARTESIAN_POINT('',(1.75E0,-5.4E0,2.5E-1));
+#3479=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3480=DIRECTION('',(1.E0,0.E0,0.E0));
+#3481=AXIS2_PLACEMENT_3D('',#3478,#3479,#3480);
+#3482=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3481);
+#3483=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3482)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3484=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3483,#3473);
+#3487=CARTESIAN_POINT('centre point',(2.25E0,-5.483905814165E0,
+4.201625611455E-1));
+#3491=CARTESIAN_POINT('',(2.25E0,-5.4E0,2.5E-1));
+#3492=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3493=DIRECTION('',(1.E0,0.E0,0.E0));
+#3494=AXIS2_PLACEMENT_3D('',#3491,#3492,#3493);
+#3495=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3494);
+#3496=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3495)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3497=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3496,#3486);
+#3500=CARTESIAN_POINT('centre point',(2.75E0,-5.483905814165E0,
+4.201625611455E-1));
+#3504=CARTESIAN_POINT('',(2.75E0,-5.4E0,2.5E-1));
+#3505=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3506=DIRECTION('',(1.E0,0.E0,0.E0));
+#3507=AXIS2_PLACEMENT_3D('',#3504,#3505,#3506);
+#3508=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3507);
+#3509=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3508)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3510=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3509,#3499);
+#3513=CARTESIAN_POINT('centre point',(3.25E0,-5.483905814165E0,
+4.201625611455E-1));
+#3517=CARTESIAN_POINT('',(3.25E0,-5.4E0,2.5E-1));
+#3518=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3519=DIRECTION('',(1.E0,0.E0,0.E0));
+#3520=AXIS2_PLACEMENT_3D('',#3517,#3518,#3519);
+#3521=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3520);
+#3522=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3521)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3523=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3522,#3512);
+#3526=CARTESIAN_POINT('centre point',(3.75E0,-5.483905814165E0,
+4.201625611455E-1));
+#3530=CARTESIAN_POINT('',(3.75E0,-5.4E0,2.5E-1));
+#3531=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3532=DIRECTION('',(1.E0,0.E0,0.E0));
+#3533=AXIS2_PLACEMENT_3D('',#3530,#3531,#3532);
+#3534=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3533);
+#3535=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3534)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3536=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3535,#3525);
+#3539=CARTESIAN_POINT('centre point',(-5.483905814165E0,-3.75E0,
+4.201625611455E-1));
+#3543=CARTESIAN_POINT('',(-5.4E0,-3.75E0,2.5E-1));
+#3544=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3545=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3546=AXIS2_PLACEMENT_3D('',#3543,#3544,#3545);
+#3547=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3546);
+#3548=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3547)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3549=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3548,#3538);
+#3552=CARTESIAN_POINT('centre point',(-5.483905814165E0,-3.25E0,
+4.201625611455E-1));
+#3556=CARTESIAN_POINT('',(-5.4E0,-3.25E0,2.5E-1));
+#3557=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3558=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3559=AXIS2_PLACEMENT_3D('',#3556,#3557,#3558);
+#3560=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3559);
+#3561=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3560)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3562=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3561,#3551);
+#3565=CARTESIAN_POINT('centre point',(-5.483905814165E0,-2.75E0,
+4.201625611455E-1));
+#3569=CARTESIAN_POINT('',(-5.4E0,-2.75E0,2.5E-1));
+#3570=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3571=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3572=AXIS2_PLACEMENT_3D('',#3569,#3570,#3571);
+#3573=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3572);
+#3574=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3573)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3575=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3574,#3564);
+#3578=CARTESIAN_POINT('centre point',(-5.483905814165E0,-2.25E0,
+4.201625611455E-1));
+#3582=CARTESIAN_POINT('',(-5.4E0,-2.25E0,2.5E-1));
+#3583=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3584=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3585=AXIS2_PLACEMENT_3D('',#3582,#3583,#3584);
+#3586=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3585);
+#3587=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3586)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3588=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3587,#3577);
+#3591=CARTESIAN_POINT('centre point',(-5.483905814165E0,-1.75E0,
+4.201625611455E-1));
+#3595=CARTESIAN_POINT('',(-5.4E0,-1.75E0,2.5E-1));
+#3596=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3597=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3598=AXIS2_PLACEMENT_3D('',#3595,#3596,#3597);
+#3599=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3598);
+#3600=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3599)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3601=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3600,#3590);
+#3604=CARTESIAN_POINT('centre point',(-5.483905814165E0,-1.25E0,
+4.201625611455E-1));
+#3608=CARTESIAN_POINT('',(-5.4E0,-1.25E0,2.5E-1));
+#3609=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3610=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3611=AXIS2_PLACEMENT_3D('',#3608,#3609,#3610);
+#3612=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3611);
+#3613=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3612)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3614=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3613,#3603);
+#3617=CARTESIAN_POINT('centre point',(-5.483905814165E0,-7.5E-1,
+4.201625611455E-1));
+#3621=CARTESIAN_POINT('',(-5.4E0,-7.5E-1,2.5E-1));
+#3622=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3623=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3624=AXIS2_PLACEMENT_3D('',#3621,#3622,#3623);
+#3625=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3624);
+#3626=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3625)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3627=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3626,#3616);
+#3630=CARTESIAN_POINT('centre point',(-5.483905814165E0,-2.5E-1,
+4.201625611455E-1));
+#3634=CARTESIAN_POINT('',(-5.4E0,-2.5E-1,2.5E-1));
+#3635=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3636=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3637=AXIS2_PLACEMENT_3D('',#3634,#3635,#3636);
+#3638=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3637);
+#3639=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3638)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3640=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3639,#3629);
+#3643=CARTESIAN_POINT('centre point',(-5.483905814165E0,2.5E-1,
+4.201625611455E-1));
+#3647=CARTESIAN_POINT('',(-5.4E0,2.5E-1,2.5E-1));
+#3648=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3649=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3650=AXIS2_PLACEMENT_3D('',#3647,#3648,#3649);
+#3651=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3650);
+#3652=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3651)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3653=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3652,#3642);
+#3656=CARTESIAN_POINT('centre point',(-5.483905814165E0,7.5E-1,
+4.201625611455E-1));
+#3660=CARTESIAN_POINT('',(-5.4E0,7.5E-1,2.5E-1));
+#3661=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3662=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3663=AXIS2_PLACEMENT_3D('',#3660,#3661,#3662);
+#3664=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3663);
+#3665=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3664)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3666=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3665,#3655);
+#3669=CARTESIAN_POINT('centre point',(-5.483905814165E0,1.25E0,
+4.201625611455E-1));
+#3673=CARTESIAN_POINT('',(-5.4E0,1.25E0,2.5E-1));
+#3674=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3675=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3676=AXIS2_PLACEMENT_3D('',#3673,#3674,#3675);
+#3677=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3676);
+#3678=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3677)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3679=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3678,#3668);
+#3682=CARTESIAN_POINT('centre point',(-5.483905814165E0,1.75E0,
+4.201625611455E-1));
+#3686=CARTESIAN_POINT('',(-5.4E0,1.75E0,2.5E-1));
+#3687=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3688=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3689=AXIS2_PLACEMENT_3D('',#3686,#3687,#3688);
+#3690=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3689);
+#3691=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3690)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3692=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3691,#3681);
+#3695=CARTESIAN_POINT('centre point',(-5.483905814165E0,2.25E0,
+4.201625611455E-1));
+#3699=CARTESIAN_POINT('',(-5.4E0,2.25E0,2.5E-1));
+#3700=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3701=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3702=AXIS2_PLACEMENT_3D('',#3699,#3700,#3701);
+#3703=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3702);
+#3704=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3703)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3705=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3704,#3694);
+#3708=CARTESIAN_POINT('centre point',(-5.483905814165E0,2.75E0,
+4.201625611455E-1));
+#3712=CARTESIAN_POINT('',(-5.4E0,2.75E0,2.5E-1));
+#3713=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3714=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3715=AXIS2_PLACEMENT_3D('',#3712,#3713,#3714);
+#3716=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3715);
+#3717=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3716)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3718=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3717,#3707);
+#3721=CARTESIAN_POINT('centre point',(-5.483905814165E0,3.25E0,
+4.201625611455E-1));
+#3725=CARTESIAN_POINT('',(-5.4E0,3.25E0,2.5E-1));
+#3726=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3727=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3728=AXIS2_PLACEMENT_3D('',#3725,#3726,#3727);
+#3729=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3728);
+#3730=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3729)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3731=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3730,#3720);
+#3734=CARTESIAN_POINT('centre point',(-5.483905814165E0,3.75E0,
+4.201625611455E-1));
+#3738=CARTESIAN_POINT('',(-5.4E0,3.75E0,2.5E-1));
+#3739=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3740=DIRECTION('',(0.E0,-1.E0,0.E0));
+#3741=AXIS2_PLACEMENT_3D('',#3738,#3739,#3740);
+#3742=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3741);
+#3743=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3742)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3744=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3743,#3733);
+#3747=CARTESIAN_POINT('centre point',(3.75E0,5.483905814165E0,
+4.201625611455E-1));
+#3751=CARTESIAN_POINT('',(3.75E0,5.4E0,2.5E-1));
+#3752=DIRECTION('',(0.E0,1.E0,0.E0));
+#3753=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3754=AXIS2_PLACEMENT_3D('',#3751,#3752,#3753);
+#3755=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3754);
+#3756=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3755)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3757=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3756,#3746);
+#3760=CARTESIAN_POINT('centre point',(3.25E0,5.483905814165E0,
+4.201625611455E-1));
+#3764=CARTESIAN_POINT('',(3.25E0,5.4E0,2.5E-1));
+#3765=DIRECTION('',(0.E0,1.E0,0.E0));
+#3766=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3767=AXIS2_PLACEMENT_3D('',#3764,#3765,#3766);
+#3768=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3767);
+#3769=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3768)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3770=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3769,#3759);
+#3773=CARTESIAN_POINT('centre point',(2.75E0,5.483905814165E0,
+4.201625611455E-1));
+#3777=CARTESIAN_POINT('',(2.75E0,5.4E0,2.5E-1));
+#3778=DIRECTION('',(0.E0,1.E0,0.E0));
+#3779=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3780=AXIS2_PLACEMENT_3D('',#3777,#3778,#3779);
+#3781=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3780);
+#3782=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3781)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3783=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3782,#3772);
+#3786=CARTESIAN_POINT('centre point',(2.25E0,5.483905814165E0,
+4.201625611455E-1));
+#3790=CARTESIAN_POINT('',(2.25E0,5.4E0,2.5E-1));
+#3791=DIRECTION('',(0.E0,1.E0,0.E0));
+#3792=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3793=AXIS2_PLACEMENT_3D('',#3790,#3791,#3792);
+#3794=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3793);
+#3795=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3794)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3796=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3795,#3785);
+#3799=CARTESIAN_POINT('centre point',(1.75E0,5.483905814165E0,
+4.201625611455E-1));
+#3803=CARTESIAN_POINT('',(1.75E0,5.4E0,2.5E-1));
+#3804=DIRECTION('',(0.E0,1.E0,0.E0));
+#3805=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3806=AXIS2_PLACEMENT_3D('',#3803,#3804,#3805);
+#3807=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3806);
+#3808=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3807)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3809=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3808,#3798);
+#3812=CARTESIAN_POINT('centre point',(1.25E0,5.483905814165E0,
+4.201625611455E-1));
+#3816=CARTESIAN_POINT('',(1.25E0,5.4E0,2.5E-1));
+#3817=DIRECTION('',(0.E0,1.E0,0.E0));
+#3818=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3819=AXIS2_PLACEMENT_3D('',#3816,#3817,#3818);
+#3820=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3819);
+#3821=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3820)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3822=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3821,#3811);
+#3825=CARTESIAN_POINT('centre point',(7.5E-1,5.483905814165E0,
+4.201625611455E-1));
+#3829=CARTESIAN_POINT('',(7.5E-1,5.4E0,2.5E-1));
+#3830=DIRECTION('',(0.E0,1.E0,0.E0));
+#3831=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3832=AXIS2_PLACEMENT_3D('',#3829,#3830,#3831);
+#3833=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3832);
+#3834=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3833)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3835=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3834,#3824);
+#3838=CARTESIAN_POINT('centre point',(2.5E-1,5.483905814165E0,
+4.201625611455E-1));
+#3842=CARTESIAN_POINT('',(2.5E-1,5.4E0,2.5E-1));
+#3843=DIRECTION('',(0.E0,1.E0,0.E0));
+#3844=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3845=AXIS2_PLACEMENT_3D('',#3842,#3843,#3844);
+#3846=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3845);
+#3847=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3846)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3848=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3847,#3837);
+#3851=CARTESIAN_POINT('centre point',(-2.5E-1,5.483905814165E0,
+4.201625611455E-1));
+#3855=CARTESIAN_POINT('',(-2.5E-1,5.4E0,2.5E-1));
+#3856=DIRECTION('',(0.E0,1.E0,0.E0));
+#3857=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3858=AXIS2_PLACEMENT_3D('',#3855,#3856,#3857);
+#3859=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3858);
+#3860=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3859)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3861=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3860,#3850);
+#3864=CARTESIAN_POINT('centre point',(-7.5E-1,5.483905814165E0,
+4.201625611455E-1));
+#3868=CARTESIAN_POINT('',(-7.5E-1,5.4E0,2.5E-1));
+#3869=DIRECTION('',(0.E0,1.E0,0.E0));
+#3870=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3871=AXIS2_PLACEMENT_3D('',#3868,#3869,#3870);
+#3872=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3871);
+#3873=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3872)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3874=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3873,#3863);
+#3877=CARTESIAN_POINT('centre point',(-1.25E0,5.483905814165E0,
+4.201625611455E-1));
+#3881=CARTESIAN_POINT('',(-1.25E0,5.4E0,2.5E-1));
+#3882=DIRECTION('',(0.E0,1.E0,0.E0));
+#3883=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3884=AXIS2_PLACEMENT_3D('',#3881,#3882,#3883);
+#3885=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3884);
+#3886=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3885)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3887=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3886,#3876);
+#3890=CARTESIAN_POINT('centre point',(-1.75E0,5.483905814165E0,
+4.201625611455E-1));
+#3894=CARTESIAN_POINT('',(-1.75E0,5.4E0,2.5E-1));
+#3895=DIRECTION('',(0.E0,1.E0,0.E0));
+#3896=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3897=AXIS2_PLACEMENT_3D('',#3894,#3895,#3896);
+#3898=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3897);
+#3899=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3898)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3900=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3899,#3889);
+#3903=CARTESIAN_POINT('centre point',(-2.25E0,5.483905814165E0,
+4.201625611455E-1));
+#3907=CARTESIAN_POINT('',(-2.25E0,5.4E0,2.5E-1));
+#3908=DIRECTION('',(0.E0,1.E0,0.E0));
+#3909=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3910=AXIS2_PLACEMENT_3D('',#3907,#3908,#3909);
+#3911=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3910);
+#3912=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3911)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3913=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3912,#3902);
+#3916=CARTESIAN_POINT('centre point',(-2.75E0,5.483905814165E0,
+4.201625611455E-1));
+#3920=CARTESIAN_POINT('',(-2.75E0,5.4E0,2.5E-1));
+#3921=DIRECTION('',(0.E0,1.E0,0.E0));
+#3922=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3923=AXIS2_PLACEMENT_3D('',#3920,#3921,#3922);
+#3924=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3923);
+#3925=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3924)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3926=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3925,#3915);
+#3929=CARTESIAN_POINT('centre point',(-3.25E0,5.483905814165E0,
+4.201625611455E-1));
+#3933=CARTESIAN_POINT('',(-3.25E0,5.4E0,2.5E-1));
+#3934=DIRECTION('',(0.E0,1.E0,0.E0));
+#3935=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3936=AXIS2_PLACEMENT_3D('',#3933,#3934,#3935);
+#3937=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3936);
+#3938=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3937)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3939=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3938,#3928);
+#3942=CARTESIAN_POINT('centre point',(-3.75E0,5.483905814165E0,
+4.201625611455E-1));
+#3946=CARTESIAN_POINT('',(-3.75E0,5.4E0,2.5E-1));
+#3947=DIRECTION('',(0.E0,1.E0,0.E0));
+#3948=DIRECTION('',(-1.E0,0.E0,0.E0));
+#3949=AXIS2_PLACEMENT_3D('',#3946,#3947,#3948);
+#3950=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3949);
+#3951=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3950)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3952=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3951,#3941);
+#3955=CARTESIAN_POINT('centre point',(5.483905814165E0,3.75E0,
+4.201625611455E-1));
+#3959=CARTESIAN_POINT('',(5.4E0,3.75E0,2.5E-1));
+#3960=DIRECTION('',(1.E0,0.E0,0.E0));
+#3961=DIRECTION('',(0.E0,1.E0,0.E0));
+#3962=AXIS2_PLACEMENT_3D('',#3959,#3960,#3961);
+#3963=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3962);
+#3964=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3963)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3965=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3964,#3954);
+#3968=CARTESIAN_POINT('centre point',(5.483905814165E0,3.25E0,
+4.201625611455E-1));
+#3972=CARTESIAN_POINT('',(5.4E0,3.25E0,2.5E-1));
+#3973=DIRECTION('',(1.E0,0.E0,0.E0));
+#3974=DIRECTION('',(0.E0,1.E0,0.E0));
+#3975=AXIS2_PLACEMENT_3D('',#3972,#3973,#3974);
+#3976=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3975);
+#3977=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3976)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3978=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3977,#3967);
+#3981=CARTESIAN_POINT('centre point',(5.483905814165E0,2.75E0,
+4.201625611455E-1));
+#3985=CARTESIAN_POINT('',(5.4E0,2.75E0,2.5E-1));
+#3986=DIRECTION('',(1.E0,0.E0,0.E0));
+#3987=DIRECTION('',(0.E0,1.E0,0.E0));
+#3988=AXIS2_PLACEMENT_3D('',#3985,#3986,#3987);
+#3989=ITEM_DEFINED_TRANSFORMATION('','',#3281,#3988);
+#3990=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#3989)SHAPE_REPRESENTATION_RELATIONSHIP());
+#3991=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#3990,#3980);
+#3994=CARTESIAN_POINT('centre point',(5.483905814165E0,2.25E0,
+4.201625611455E-1));
+#3998=CARTESIAN_POINT('',(5.4E0,2.25E0,2.5E-1));
+#3999=DIRECTION('',(1.E0,0.E0,0.E0));
+#4000=DIRECTION('',(0.E0,1.E0,0.E0));
+#4001=AXIS2_PLACEMENT_3D('',#3998,#3999,#4000);
+#4002=ITEM_DEFINED_TRANSFORMATION('','',#3281,#4001);
+#4003=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#4002)SHAPE_REPRESENTATION_RELATIONSHIP());
+#4004=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#4003,#3993);
+#4007=CARTESIAN_POINT('centre point',(5.483905814165E0,1.75E0,
+4.201625611455E-1));
+#4011=CARTESIAN_POINT('',(5.4E0,1.75E0,2.5E-1));
+#4012=DIRECTION('',(1.E0,0.E0,0.E0));
+#4013=DIRECTION('',(0.E0,1.E0,0.E0));
+#4014=AXIS2_PLACEMENT_3D('',#4011,#4012,#4013);
+#4015=ITEM_DEFINED_TRANSFORMATION('','',#3281,#4014);
+#4016=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#4015)SHAPE_REPRESENTATION_RELATIONSHIP());
+#4017=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#4016,#4006);
+#4020=CARTESIAN_POINT('centre point',(5.483905814165E0,1.25E0,
+4.201625611455E-1));
+#4024=CARTESIAN_POINT('',(5.4E0,1.25E0,2.5E-1));
+#4025=DIRECTION('',(1.E0,0.E0,0.E0));
+#4026=DIRECTION('',(0.E0,1.E0,0.E0));
+#4027=AXIS2_PLACEMENT_3D('',#4024,#4025,#4026);
+#4028=ITEM_DEFINED_TRANSFORMATION('','',#3281,#4027);
+#4029=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#4028)SHAPE_REPRESENTATION_RELATIONSHIP());
+#4030=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#4029,#4019);
+#4033=CARTESIAN_POINT('centre point',(5.483905814165E0,7.5E-1,
+4.201625611455E-1));
+#4037=CARTESIAN_POINT('',(5.4E0,7.5E-1,2.5E-1));
+#4038=DIRECTION('',(1.E0,0.E0,0.E0));
+#4039=DIRECTION('',(0.E0,1.E0,0.E0));
+#4040=AXIS2_PLACEMENT_3D('',#4037,#4038,#4039);
+#4041=ITEM_DEFINED_TRANSFORMATION('','',#3281,#4040);
+#4042=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#4041)SHAPE_REPRESENTATION_RELATIONSHIP());
+#4043=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#4042,#4032);
+#4046=CARTESIAN_POINT('centre point',(5.483905814165E0,2.5E-1,
+4.201625611455E-1));
+#4050=CARTESIAN_POINT('',(5.4E0,2.5E-1,2.5E-1));
+#4051=DIRECTION('',(1.E0,0.E0,0.E0));
+#4052=DIRECTION('',(0.E0,1.E0,0.E0));
+#4053=AXIS2_PLACEMENT_3D('',#4050,#4051,#4052);
+#4054=ITEM_DEFINED_TRANSFORMATION('','',#3281,#4053);
+#4055=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#4054)SHAPE_REPRESENTATION_RELATIONSHIP());
+#4056=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#4055,#4045);
+#4059=CARTESIAN_POINT('centre point',(5.483905814165E0,-2.5E-1,
+4.201625611455E-1));
+#4063=CARTESIAN_POINT('',(5.4E0,-2.5E-1,2.5E-1));
+#4064=DIRECTION('',(1.E0,0.E0,0.E0));
+#4065=DIRECTION('',(0.E0,1.E0,0.E0));
+#4066=AXIS2_PLACEMENT_3D('',#4063,#4064,#4065);
+#4067=ITEM_DEFINED_TRANSFORMATION('','',#3281,#4066);
+#4068=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#4067)SHAPE_REPRESENTATION_RELATIONSHIP());
+#4069=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#4068,#4058);
+#4072=CARTESIAN_POINT('centre point',(5.483905814165E0,-7.5E-1,
+4.201625611455E-1));
+#4076=CARTESIAN_POINT('',(5.4E0,-7.5E-1,2.5E-1));
+#4077=DIRECTION('',(1.E0,0.E0,0.E0));
+#4078=DIRECTION('',(0.E0,1.E0,0.E0));
+#4079=AXIS2_PLACEMENT_3D('',#4076,#4077,#4078);
+#4080=ITEM_DEFINED_TRANSFORMATION('','',#3281,#4079);
+#4081=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#4080)SHAPE_REPRESENTATION_RELATIONSHIP());
+#4082=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#4081,#4071);
+#4085=CARTESIAN_POINT('centre point',(5.483905814165E0,-1.25E0,
+4.201625611455E-1));
+#4089=CARTESIAN_POINT('',(5.4E0,-1.25E0,2.5E-1));
+#4090=DIRECTION('',(1.E0,0.E0,0.E0));
+#4091=DIRECTION('',(0.E0,1.E0,0.E0));
+#4092=AXIS2_PLACEMENT_3D('',#4089,#4090,#4091);
+#4093=ITEM_DEFINED_TRANSFORMATION('','',#3281,#4092);
+#4094=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#4093)SHAPE_REPRESENTATION_RELATIONSHIP());
+#4095=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#4094,#4084);
+#4098=CARTESIAN_POINT('centre point',(5.483905814165E0,-1.75E0,
+4.201625611455E-1));
+#4102=CARTESIAN_POINT('',(5.4E0,-1.75E0,2.5E-1));
+#4103=DIRECTION('',(1.E0,0.E0,0.E0));
+#4104=DIRECTION('',(0.E0,1.E0,0.E0));
+#4105=AXIS2_PLACEMENT_3D('',#4102,#4103,#4104);
+#4106=ITEM_DEFINED_TRANSFORMATION('','',#3281,#4105);
+#4107=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#4106)SHAPE_REPRESENTATION_RELATIONSHIP());
+#4108=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#4107,#4097);
+#4111=CARTESIAN_POINT('centre point',(5.483905814165E0,-2.25E0,
+4.201625611455E-1));
+#4115=CARTESIAN_POINT('',(5.4E0,-2.25E0,2.5E-1));
+#4116=DIRECTION('',(1.E0,0.E0,0.E0));
+#4117=DIRECTION('',(0.E0,1.E0,0.E0));
+#4118=AXIS2_PLACEMENT_3D('',#4115,#4116,#4117);
+#4119=ITEM_DEFINED_TRANSFORMATION('','',#3281,#4118);
+#4120=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#4119)SHAPE_REPRESENTATION_RELATIONSHIP());
+#4121=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#4120,#4110);
+#4124=CARTESIAN_POINT('centre point',(5.483905814165E0,-2.75E0,
+4.201625611455E-1));
+#4128=CARTESIAN_POINT('',(5.4E0,-2.75E0,2.5E-1));
+#4129=DIRECTION('',(1.E0,0.E0,0.E0));
+#4130=DIRECTION('',(0.E0,1.E0,0.E0));
+#4131=AXIS2_PLACEMENT_3D('',#4128,#4129,#4130);
+#4132=ITEM_DEFINED_TRANSFORMATION('','',#3281,#4131);
+#4133=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#4132)SHAPE_REPRESENTATION_RELATIONSHIP());
+#4134=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#4133,#4123);
+#4137=CARTESIAN_POINT('centre point',(5.483905814165E0,-3.25E0,
+4.201625611455E-1));
+#4141=CARTESIAN_POINT('',(5.4E0,-3.25E0,2.5E-1));
+#4142=DIRECTION('',(1.E0,0.E0,0.E0));
+#4143=DIRECTION('',(0.E0,1.E0,0.E0));
+#4144=AXIS2_PLACEMENT_3D('',#4141,#4142,#4143);
+#4145=ITEM_DEFINED_TRANSFORMATION('','',#3281,#4144);
+#4146=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#4145)SHAPE_REPRESENTATION_RELATIONSHIP());
+#4147=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#4146,#4136);
+#4150=CARTESIAN_POINT('centre point',(5.483905814165E0,-3.75E0,
+4.201625611455E-1));
+#4154=CARTESIAN_POINT('',(5.4E0,-3.75E0,2.5E-1));
+#4155=DIRECTION('',(1.E0,0.E0,0.E0));
+#4156=DIRECTION('',(0.E0,1.E0,0.E0));
+#4157=AXIS2_PLACEMENT_3D('',#4154,#4155,#4156);
+#4158=ITEM_DEFINED_TRANSFORMATION('','',#3281,#4157);
+#4159=(REPRESENTATION_RELATIONSHIP('','',#3282,#2720)REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#4158)SHAPE_REPRESENTATION_RELATIONSHIP());
+#4160=CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#4159,#4149);
+#4163=PLANE_ANGLE_MEASURE_WITH_UNIT(PLANE_ANGLE_MEASURE(1.745329251994E-2),
+#4162);
+#4164=(CONVERSION_BASED_UNIT('DEGREE',#4163)NAMED_UNIT(*)PLANE_ANGLE_UNIT());
+#4166=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.706796484743E-3),#4161,
+'distance_accuracy_value',
+'Maximum model space distance between geometric entities at asserted connectivities');
+#4168=CARTESIAN_POINT('',(0.E0,0.E0,0.E0));
+#4169=DIRECTION('',(0.E0,0.E0,1.E0));
+#4170=DIRECTION('',(1.E0,0.E0,0.E0));
+#4172=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#36,#44,#51,
+#58,#65,#72,#79,#86,#93,#100,#107,#114,#122,#130,#137,#144,#151,#158,#165,#172,
+#179,#186,#194,#202,#210,#220,#227,#234,#241,#248,#256,#264,#272,#279,#286,#293,
+#300,#310,#317,#324,#331,#338,#345,#352,#362,#369,#376,#383,#390,#397,#404,#414,
+#424,#432,#440,#448,#455,#462,#469,#476,#483,#490,#497,#504,#512,#520,#528,#536,
+#544,#552,#562,#569,#576,#583,#590,#597,#604,#611,#618,#626,#634,#642,#650,#658,
+#666,#676,#686,#693,#700,#707,#714,#721,#728,#735,#742,#749,#757,#765,#773,#783,
+#793,#800,#807,#814,#821,#828,#835,#845,#852,#859,#866,#874,#882,#890,#898,#906,
+#914,#921,#928,#935,#942,#949,#956,#963,#970,#977,#984,#991,#999,#1007,#1015,
+#1022,#1029,#1036,#1046,#1053,#1060,#1067,#1077,#1084,#1091,#1098,#1108,#1118,
+#1125,#1132,#1139,#1147,#1155,#1163,#1171,#1179,#1187,#1195,#1203,#1211,#1219,
+#1227,#1235,#1245,#1252,#1259,#1266,#1274,#1282,#1290,#27,#2741,#2748,#2755,
+#2762,#2769,#2776,#2783,#2790,#2797,#2804,#2811,#2818,#2825,#2832,#2839,#2846,
+#2853,#2861,#2868,#2876,#2883,#2890,#2897,#2905,#2912,#2920,#2927,#2935,#2942,
+#2950,#2957,#2964,#2971,#2979,#2986,#2994,#2734),#4167);
+#4173=PRODUCT_DEFINITION_CONTEXT('part definition',#2659,'design');
+#4174=PRODUCT_CONTEXT('',#2659,'mechanical');
+#4175=PRODUCT('PM0064A_ASM','PM0064A_ASM','NOT SPECIFIED',(#4174));
+#4176=PRODUCT_DEFINITION_FORMATION('206','LAST_VERSION',#4175);
+#4179=DERIVED_UNIT_ELEMENT(#4178,2.E0);
+#4180=DERIVED_UNIT((#4179));
+#4181=MEASURE_REPRESENTATION_ITEM('surface area measure',AREA_MEASURE(
+3.189794185978E2),#4180);
+#4186=DERIVED_UNIT_ELEMENT(#4185,3.E0);
+#4187=DERIVED_UNIT((#4186));
+#4188=MEASURE_REPRESENTATION_ITEM('volume measure',VOLUME_MEASURE(
+1.404582680576E2),#4187);
+#4192=CARTESIAN_POINT('centre point',(3.005540293577E-4,-3.005553863951E-4,
+7.922925581419E-1));
+#4196=PRODUCT_RELATED_PRODUCT_CATEGORY('part','',(#4175,#2663,#3284));
+#4198=GENERAL_PROPERTY('','AUTHOR','user defined attribute');
+#4199=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4198,#4197);
+#4200=DESCRIPTIVE_REPRESENTATION_ITEM('AUTHOR','T. LEQUANG');
+#4204=GENERAL_PROPERTY('','DATE','user defined attribute');
+#4205=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4204,#4203);
+#4206=DESCRIPTIVE_REPRESENTATION_ITEM('DATE','03/03/2017');
+#4210=GENERAL_PROPERTY('','DWG_NO','user defined attribute');
+#4211=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4210,#4209);
+#4212=DESCRIPTIVE_REPRESENTATION_ITEM('DWG_NO','4215162');
+#4216=GENERAL_PROPERTY('','REV','user defined attribute');
+#4217=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4216,#4215);
+#4218=DESCRIPTIVE_REPRESENTATION_ITEM('REV','A');
+#4222=GENERAL_PROPERTY('','TITLE','user defined attribute');
+#4223=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4222,#4221);
+#4225=GENERAL_PROPERTY('','DCHK','user defined attribute');
+#4226=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4225,#4224);
+#4227=DESCRIPTIVE_REPRESENTATION_ITEM('DCHK','K. SINCERBOX');
+#4231=GENERAL_PROPERTY('','DCHK_DATE','user defined attribute');
+#4232=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4231,#4230);
+#4233=DESCRIPTIVE_REPRESENTATION_ITEM('DCHK_DATE','02/03/2017');
+#4237=GENERAL_PROPERTY('','ECHK','user defined attribute');
+#4238=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4237,#4236);
+#4239=DESCRIPTIVE_REPRESENTATION_ITEM('ECHK','P. GALICKI');
+#4243=GENERAL_PROPERTY('','ECHK_DATE','user defined attribute');
+#4244=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4243,#4242);
+#4245=DESCRIPTIVE_REPRESENTATION_ITEM('ECHK_DATE','03/03/2017');
+#4249=GENERAL_PROPERTY('','LD_PITCH','user defined attribute');
+#4250=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4249,#4248);
+#4251=VALUE_REPRESENTATION_ITEM('LD_PITCH',NUMERIC_MEASURE(5.E-1));
+#4254=DESCRIPTIVE_REPRESENTATION_ITEM('attribute description','Real Number');
+#4259=GENERAL_PROPERTY('','RELEASED','user defined attribute');
+#4260=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4259,#4258);
+#4261=DESCRIPTIVE_REPRESENTATION_ITEM('RELEASED','WDM');
+#4265=GENERAL_PROPERTY('','REL_DATE','user defined attribute');
+#4266=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4265,#4264);
+#4267=DESCRIPTIVE_REPRESENTATION_ITEM('REL_DATE','03/03/2017');
+#4271=GENERAL_PROPERTY('','DESIGNER','user defined attribute');
+#4272=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4271,#4270);
+#4273=DESCRIPTIVE_REPRESENTATION_ITEM('DESIGNER','');
+#4277=GENERAL_PROPERTY('','DES_DATE','user defined attribute');
+#4278=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4277,#4276);
+#4279=DESCRIPTIVE_REPRESENTATION_ITEM('DES_DATE','');
+#4283=GENERAL_PROPERTY('','APPROVER','user defined attribute');
+#4284=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4283,#4282);
+#4285=DESCRIPTIVE_REPRESENTATION_ITEM('APPROVER','E. REY & D. CHIN ');
+#4289=GENERAL_PROPERTY('','APP_DATE','user defined attribute');
+#4290=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4289,#4288);
+#4291=DESCRIPTIVE_REPRESENTATION_ITEM('APP_DATE','03/01/2017');
+#4295=GENERAL_PROPERTY('','DESG','user defined attribute');
+#4296=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4295,#4294);
+#4297=DESCRIPTIVE_REPRESENTATION_ITEM('DESG','PM0064A');
+#4301=GENERAL_PROPERTY('','TI_PACKAGE_NAME','user defined attribute');
+#4302=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4301,#4300);
+#4303=DESCRIPTIVE_REPRESENTATION_ITEM('TI_PACKAGE_NAME',
+'LQFP - 1.6 mm max height');
+#4307=GENERAL_PROPERTY('','INDUSTRY_NAME','user defined attribute');
+#4308=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4307,#4306);
+#4309=DESCRIPTIVE_REPRESENTATION_ITEM('INDUSTRY_NAME','PLASTIC QUAD FLATPACK');
+#4313=GENERAL_PROPERTY('','LD_CNT','user defined attribute');
+#4314=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4313,#4312);
+#4315=VALUE_REPRESENTATION_ITEM('LD_CNT',NUMERIC_MEASURE(6.4E1));
+#4318=DESCRIPTIVE_REPRESENTATION_ITEM('attribute description','Real Number');
+#4323=GENERAL_PROPERTY('','LDNO2','user defined attribute');
+#4324=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4323,#4322);
+#4325=VALUE_REPRESENTATION_ITEM('LDNO2',NUMERIC_MEASURE(1.6E1));
+#4328=DESCRIPTIVE_REPRESENTATION_ITEM('attribute description','Real Number');
+#4333=GENERAL_PROPERTY('','LDNO3','user defined attribute');
+#4334=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4333,#4332);
+#4335=VALUE_REPRESENTATION_ITEM('LDNO3',NUMERIC_MEASURE(1.7E1));
+#4338=DESCRIPTIVE_REPRESENTATION_ITEM('attribute description','Real Number');
+#4343=GENERAL_PROPERTY('','LDNO4','user defined attribute');
+#4344=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4343,#4342);
+#4345=VALUE_REPRESENTATION_ITEM('LDNO4',NUMERIC_MEASURE(3.2E1));
+#4348=DESCRIPTIVE_REPRESENTATION_ITEM('attribute description','Real Number');
+#4353=GENERAL_PROPERTY('','LDNO5','user defined attribute');
+#4354=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4353,#4352);
+#4355=VALUE_REPRESENTATION_ITEM('LDNO5',NUMERIC_MEASURE(3.3E1));
+#4358=DESCRIPTIVE_REPRESENTATION_ITEM('attribute description','Real Number');
+#4363=GENERAL_PROPERTY('','LDNO6','user defined attribute');
+#4364=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4363,#4362);
+#4365=VALUE_REPRESENTATION_ITEM('LDNO6',NUMERIC_MEASURE(4.8E1));
+#4368=DESCRIPTIVE_REPRESENTATION_ITEM('attribute description','Real Number');
+#4373=GENERAL_PROPERTY('','LDNO7','user defined attribute');
+#4374=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4373,#4372);
+#4375=VALUE_REPRESENTATION_ITEM('LDNO7',NUMERIC_MEASURE(4.9E1));
+#4378=DESCRIPTIVE_REPRESENTATION_ITEM('attribute description','Real Number');
+#4383=GENERAL_PROPERTY('','LDPITCH_CNT','user defined attribute');
+#4384=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4383,#4382);
+#4385=VALUE_REPRESENTATION_ITEM('LDPITCH_CNT',NUMERIC_MEASURE(6.E1));
+#4388=DESCRIPTIVE_REPRESENTATION_ITEM('attribute description','Real Number');
+#4393=GENERAL_PROPERTY('','AMAX','user defined attribute');
+#4394=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4393,#4392);
+#4395=VALUE_REPRESENTATION_ITEM('AMAX',NUMERIC_MEASURE(1.6E0));
+#4398=DESCRIPTIVE_REPRESENTATION_ITEM('attribute description','Real Number');
+#4403=GENERAL_PROPERTY('','PKG_NAME','user defined attribute');
+#4404=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4403,#4402);
+#4405=DESCRIPTIVE_REPRESENTATION_ITEM('PKG_NAME','LQFP');
+#4409=GENERAL_PROPERTY('','MM_YYYY','user defined attribute');
+#4410=GENERAL_PROPERTY_ASSOCIATION('user defined attribute','',#4409,#4408);
+#4411=DESCRIPTIVE_REPRESENTATION_ITEM('MM_YYYY','03/2017');
+#1=COLOUR_RGB('',0.E0,4.3E-1,1.E0);
+#2=COLOUR_RGB('',0.E0,6.6E-1,0.E0);
+#3=COLOUR_RGB('',1.29412E-1,5.E-2,1.E-1);
+#4=COLOUR_RGB('',1.80392E-1,2.7451E-1,9.8039E-2);
+#5=COLOUR_RGB('',2.54902E-1,5.4902E-1,0.E0);
+#6=COLOUR_RGB('',2.7451E-1,2.7451E-1,2.7451E-1);
+#7=COLOUR_RGB('',3.E-1,1.29412E-1,2.5098E-1);
+#8=COLOUR_RGB('',3.13725E-1,3.13725E-1,3.13725E-1);
+#9=COLOUR_RGB('',3.5E-1,3.5E-1,3.5E-1);
+#10=COLOUR_RGB('',3.92157E-1,3.92157E-1,3.92157E-1);
+#11=COLOUR_RGB('',5.7E-1,0.E0,1.E0);
+#12=COLOUR_RGB('',5.9E-1,3.E-1,0.E0);
+#13=COLOUR_RGB('',6.E-1,6.E-1,6.E-1);
+#14=COLOUR_RGB('',6.9E-1,0.E0,0.E0);
+#15=COLOUR_RGB('',6.952E-1,7.426E-1,7.9E-1);
+#16=COLOUR_RGB('',7.E-1,7.E-1,7.E-1);
+#17=COLOUR_RGB('',7.45098E-1,3.92157E-1,2.94118E-1);
+#18=COLOUR_RGB('',8.27451E-1,3.29412E-1,7.0588E-2);
+#19=COLOUR_RGB('',8.39216E-1,8.90196E-1,7.68627E-1);
+#20=COLOUR_RGB('',8.7E-1,7.5E-1,4.9E-1);
+#21=COLOUR_RGB('',8.9E-1,9.2E-1,9.4E-1);
+#22=COLOUR_RGB('',9.80392E-1,9.80392E-1,9.80392E-1);
+#23=COLOUR_RGB('',9.9E-1,1.E0,0.E0);
+#24=COLOUR_RGB('',1.E0,5.E-1,0.E0);
+#25=COLOUR_RGB('',1.E0,7.84314E-1,0.E0);
+#26=DRAUGHTING_PRE_DEFINED_COLOUR('white');
+#32=CIRCLE('',#31,2.5E-1);
+#41=CIRCLE('',#40,2.5E-1);
+#119=CIRCLE('',#118,2.5E-1);
+#127=CIRCLE('',#126,2.5E-1);
+#191=CIRCLE('',#190,1.E-1);
+#199=CIRCLE('',#198,1.E-1);
+#207=CIRCLE('',#206,1.E-1);
+#217=B_SPLINE_CURVE_WITH_KNOTS('',3,(#211,#212,#213,#214,#215,#216),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#253=CIRCLE('',#252,1.E-1);
+#261=CIRCLE('',#260,1.E-1);
+#269=CIRCLE('',#268,1.E-1);
+#307=B_SPLINE_CURVE_WITH_KNOTS('',3,(#301,#302,#303,#304,#305,#306),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#359=B_SPLINE_CURVE_WITH_KNOTS('',3,(#353,#354,#355,#356,#357,#358),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#411=B_SPLINE_CURVE_WITH_KNOTS('',3,(#405,#406,#407,#408,#409,#410),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#421=B_SPLINE_CURVE_WITH_KNOTS('',3,(#415,#416,#417,#418,#419,#420),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#429=CIRCLE('',#428,1.E-1);
+#437=CIRCLE('',#436,1.E-1);
+#445=CIRCLE('',#444,1.E-1);
+#509=CIRCLE('',#508,1.E-1);
+#517=CIRCLE('',#516,1.E-1);
+#525=CIRCLE('',#524,1.E-1);
+#533=CIRCLE('',#532,1.E-1);
+#541=CIRCLE('',#540,1.E-1);
+#549=CIRCLE('',#548,1.E-1);
+#559=B_SPLINE_CURVE_WITH_KNOTS('',3,(#553,#554,#555,#556,#557,#558),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#623=CIRCLE('',#622,1.E-1);
+#631=CIRCLE('',#630,1.E-1);
+#639=CIRCLE('',#638,1.E-1);
+#647=CIRCLE('',#646,1.E-1);
+#655=CIRCLE('',#654,1.E-1);
+#663=CIRCLE('',#662,1.E-1);
+#673=B_SPLINE_CURVE_WITH_KNOTS('',3,(#667,#668,#669,#670,#671,#672),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#683=B_SPLINE_CURVE_WITH_KNOTS('',3,(#677,#678,#679,#680,#681,#682),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#754=CIRCLE('',#753,1.E-1);
+#762=CIRCLE('',#761,1.E-1);
+#770=CIRCLE('',#769,1.E-1);
+#780=B_SPLINE_CURVE_WITH_KNOTS('',3,(#774,#775,#776,#777,#778,#779),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#790=B_SPLINE_CURVE_WITH_KNOTS('',3,(#784,#785,#786,#787,#788,#789),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#842=B_SPLINE_CURVE_WITH_KNOTS('',3,(#836,#837,#838,#839,#840,#841),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#871=CIRCLE('',#870,1.E-1);
+#879=CIRCLE('',#878,1.E-1);
+#887=CIRCLE('',#886,1.E-1);
+#895=CIRCLE('',#894,1.E-1);
+#903=CIRCLE('',#902,1.E-1);
+#911=CIRCLE('',#910,1.E-1);
+#996=CIRCLE('',#995,1.E-1);
+#1004=CIRCLE('',#1003,1.E-1);
+#1012=CIRCLE('',#1011,1.E-1);
+#1043=B_SPLINE_CURVE_WITH_KNOTS('',3,(#1037,#1038,#1039,#1040,#1041,#1042),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#1074=B_SPLINE_CURVE_WITH_KNOTS('',3,(#1068,#1069,#1070,#1071,#1072,#1073),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#1105=B_SPLINE_CURVE_WITH_KNOTS('',3,(#1099,#1100,#1101,#1102,#1103,#1104),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#1115=B_SPLINE_CURVE_WITH_KNOTS('',3,(#1109,#1110,#1111,#1112,#1113,#1114),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#1144=CIRCLE('',#1143,1.E-1);
+#1152=CIRCLE('',#1151,1.E-1);
+#1160=CIRCLE('',#1159,1.E-1);
+#1168=CIRCLE('',#1167,1.E-1);
+#1176=CIRCLE('',#1175,1.E-1);
+#1184=CIRCLE('',#1183,1.E-1);
+#1192=CIRCLE('',#1191,1.E-1);
+#1200=CIRCLE('',#1199,1.E-1);
+#1208=CIRCLE('',#1207,1.E-1);
+#1216=CIRCLE('',#1215,1.E-1);
+#1224=CIRCLE('',#1223,1.E-1);
+#1232=CIRCLE('',#1231,1.E-1);
+#1242=B_SPLINE_CURVE_WITH_KNOTS('',3,(#1236,#1237,#1238,#1239,#1240,#1241),
+.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.E0,3.333333333333E-1,6.666666666667E-1,1.E0),
+.UNSPECIFIED.);
+#1271=CIRCLE('',#1270,1.E-1);
+#1279=CIRCLE('',#1278,1.E-1);
+#1287=CIRCLE('',#1286,1.E-1);
+#1464=EDGE_CURVE('',#1329,#1330,#48,.T.);
+#1466=EDGE_CURVE('',#1336,#1329,#55,.T.);
+#1468=EDGE_CURVE('',#1362,#1336,#62,.T.);
+#1470=EDGE_CURVE('',#1368,#1362,#69,.T.);
+#1472=EDGE_CURVE('',#1394,#1368,#76,.T.);
+#1474=EDGE_CURVE('',#1402,#1394,#83,.T.);
+#1476=EDGE_CURVE('',#1401,#1402,#90,.T.);
+#1478=EDGE_CURVE('',#1330,#1401,#97,.T.);
+#1482=EDGE_CURVE('',#1297,#1298,#32,.T.);
+#1484=EDGE_CURVE('',#1298,#1297,#41,.T.);
+#1488=ADVANCED_FACE('',(#1481,#1487),#1463,.T.);
+#1495=EDGE_CURVE('',#1298,#1294,#111,.T.);
+#1497=EDGE_CURVE('',#1293,#1294,#119,.T.);
+#1499=EDGE_CURVE('',#1297,#1293,#104,.T.);
+#1503=ADVANCED_FACE('',(#1502),#1493,.F.);
+#1511=EDGE_CURVE('',#1294,#1293,#127,.T.);
+#1516=ADVANCED_FACE('',(#1515),#1508,.F.);
+#1526=ADVANCED_FACE('',(#1525),#1521,.F.);
+#1532=EDGE_CURVE('',#1325,#1326,#134,.T.);
+#1534=EDGE_CURVE('',#1325,#1329,#663,.T.);
+#1537=EDGE_CURVE('',#1330,#1326,#1287,.T.);
+#1541=ADVANCED_FACE('',(#1540),#1531,.T.);
+#1548=EDGE_CURVE('',#1452,#1326,#141,.T.);
+#1550=EDGE_CURVE('',#1452,#1340,#148,.T.);
+#1552=EDGE_CURVE('',#1325,#1340,#155,.T.);
+#1556=ADVANCED_FACE('',(#1555),#1546,.T.);
+#1562=EDGE_CURVE('',#1454,#1456,#162,.T.);
+#1564=EDGE_CURVE('',#1454,#1452,#790,.T.);
+#1567=EDGE_CURVE('',#1326,#1456,#1279,.T.);
+#1571=ADVANCED_FACE('',(#1570),#1561,.T.);
+#1578=EDGE_CURVE('',#1456,#1458,#169,.T.);
+#1580=EDGE_CURVE('',#1458,#1437,#176,.T.);
+#1582=EDGE_CURVE('',#1454,#1437,#183,.T.);
+#1586=ADVANCED_FACE('',(#1585),#1576,.T.);
+#1593=EDGE_CURVE('',#1401,#1458,#199,.T.);
+#1596=EDGE_CURVE('',#1456,#1330,#1271,.T.);
+#1600=ADVANCED_FACE('',(#1599),#1591,.T.);
+#1606=EDGE_CURVE('',#1458,#1397,#191,.T.);
+#1609=EDGE_CURVE('',#1397,#1401,#207,.T.);
+#1613=ADVANCED_FACE('',(#1612),#1605,.T.);
+#1621=EDGE_CURVE('',#1397,#1441,#245,.T.);
+#1623=EDGE_CURVE('',#1437,#1441,#217,.T.);
+#1627=ADVANCED_FACE('',(#1626),#1618,.T.);
+#1633=EDGE_CURVE('',#1397,#1398,#224,.T.);
+#1635=EDGE_CURVE('',#1412,#1398,#231,.T.);
+#1637=EDGE_CURVE('',#1412,#1441,#238,.T.);
+#1642=ADVANCED_FACE('',(#1641),#1632,.T.);
+#1651=EDGE_CURVE('',#1402,#1398,#269,.T.);
+#1655=ADVANCED_FACE('',(#1654),#1647,.T.);
+#1661=EDGE_CURVE('',#1416,#1402,#253,.T.);
+#1663=EDGE_CURVE('',#1398,#1416,#261,.T.);
+#1668=ADVANCED_FACE('',(#1667),#1660,.T.);
+#1674=EDGE_CURVE('',#1416,#1418,#283,.T.);
+#1678=EDGE_CURVE('',#1394,#1418,#437,.T.);
+#1682=ADVANCED_FACE('',(#1681),#1673,.T.);
+#1688=EDGE_CURVE('',#1414,#1416,#276,.T.);
+#1691=EDGE_CURVE('',#1418,#1420,#290,.T.);
+#1693=EDGE_CURVE('',#1414,#1420,#297,.T.);
+#1697=ADVANCED_FACE('',(#1696),#1687,.T.);
+#1704=EDGE_CURVE('',#1414,#1412,#307,.T.);
+#1710=ADVANCED_FACE('',(#1709),#1702,.T.);
+#1716=EDGE_CURVE('',#1412,#1405,#314,.T.);
+#1719=EDGE_CURVE('',#1414,#1409,#387,.T.);
+#1721=EDGE_CURVE('',#1409,#1405,#359,.T.);
+#1725=ADVANCED_FACE('',(#1724),#1715,.T.);
+#1732=EDGE_CURVE('',#1442,#1405,#321,.T.);
+#1734=EDGE_CURVE('',#1441,#1442,#328,.T.);
+#1739=ADVANCED_FACE('',(#1738),#1730,.T.);
+#1745=EDGE_CURVE('',#1405,#1406,#335,.T.);
+#1747=EDGE_CURVE('',#1406,#1432,#342,.T.);
+#1749=EDGE_CURVE('',#1442,#1432,#349,.T.);
+#1754=ADVANCED_FACE('',(#1753),#1744,.T.);
+#1762=EDGE_CURVE('',#1409,#1410,#366,.T.);
+#1764=EDGE_CURVE('',#1410,#1406,#903,.T.);
+#1768=ADVANCED_FACE('',(#1767),#1759,.T.);
+#1775=EDGE_CURVE('',#1409,#1424,#401,.T.);
+#1777=EDGE_CURVE('',#1424,#1428,#373,.T.);
+#1779=EDGE_CURVE('',#1428,#1410,#380,.T.);
+#1783=ADVANCED_FACE('',(#1782),#1773,.T.);
+#1791=EDGE_CURVE('',#1420,#1424,#394,.T.);
+#1796=ADVANCED_FACE('',(#1795),#1788,.T.);
+#1803=EDGE_CURVE('',#1420,#1422,#421,.T.);
+#1805=EDGE_CURVE('',#1422,#1426,#1033,.T.);
+#1807=EDGE_CURVE('',#1424,#1426,#411,.T.);
+#1811=ADVANCED_FACE('',(#1810),#1801,.T.);
+#1818=EDGE_CURVE('',#1418,#1392,#429,.T.);
+#1820=EDGE_CURVE('',#1392,#1422,#466,.T.);
+#1825=ADVANCED_FACE('',(#1824),#1816,.T.);
+#1833=EDGE_CURVE('',#1392,#1394,#445,.T.);
+#1837=ADVANCED_FACE('',(#1836),#1830,.T.);
+#1843=EDGE_CURVE('',#1392,#1390,#473,.T.);
+#1847=EDGE_CURVE('',#1368,#1390,#509,.T.);
+#1851=ADVANCED_FACE('',(#1850),#1842,.T.);
+#1857=EDGE_CURVE('',#1386,#1390,#452,.T.);
+#1859=EDGE_CURVE('',#1422,#1386,#459,.T.);
+#1865=ADVANCED_FACE('',(#1864),#1856,.T.);
+#1871=EDGE_CURVE('',#1388,#1365,#501,.T.);
+#1873=EDGE_CURVE('',#1388,#1386,#1043,.T.);
+#1876=EDGE_CURVE('',#1390,#1365,#525,.T.);
+#1880=ADVANCED_FACE('',(#1879),#1870,.T.);
+#1886=EDGE_CURVE('',#1365,#1366,#480,.T.);
+#1888=EDGE_CURVE('',#1366,#1370,#487,.T.);
+#1890=EDGE_CURVE('',#1388,#1370,#494,.T.);
+#1895=ADVANCED_FACE('',(#1894),#1885,.T.);
+#1902=EDGE_CURVE('',#1365,#1368,#517,.T.);
+#1905=EDGE_CURVE('',#1362,#1366,#541,.T.);
+#1909=ADVANCED_FACE('',(#1908),#1900,.T.);
+#1920=ADVANCED_FACE('',(#1919),#1914,.T.);
+#1926=EDGE_CURVE('',#1366,#1360,#533,.T.);
+#1929=EDGE_CURVE('',#1360,#1362,#549,.T.);
+#1933=ADVANCED_FACE('',(#1932),#1925,.T.);
+#1941=EDGE_CURVE('',#1360,#1372,#580,.T.);
+#1943=EDGE_CURVE('',#1370,#1372,#559,.T.);
+#1947=ADVANCED_FACE('',(#1946),#1938,.T.);
+#1953=EDGE_CURVE('',#1354,#1358,#566,.T.);
+#1955=EDGE_CURVE('',#1372,#1354,#573,.T.);
+#1958=EDGE_CURVE('',#1360,#1358,#587,.T.);
+#1962=ADVANCED_FACE('',(#1961),#1952,.T.);
+#1968=EDGE_CURVE('',#1356,#1333,#615,.T.);
+#1970=EDGE_CURVE('',#1356,#1354,#1105,.T.);
+#1973=EDGE_CURVE('',#1358,#1333,#639,.T.);
+#1977=ADVANCED_FACE('',(#1976),#1967,.T.);
+#1983=EDGE_CURVE('',#1333,#1334,#594,.T.);
+#1985=EDGE_CURVE('',#1334,#1338,#601,.T.);
+#1987=EDGE_CURVE('',#1356,#1338,#608,.T.);
+#1992=ADVANCED_FACE('',(#1991),#1982,.T.);
+#1999=EDGE_CURVE('',#1333,#1336,#631,.T.);
+#2002=EDGE_CURVE('',#1329,#1334,#655,.T.);
+#2006=ADVANCED_FACE('',(#2005),#1997,.T.);
+#2012=EDGE_CURVE('',#1336,#1358,#623,.T.);
+#2018=ADVANCED_FACE('',(#2017),#2011,.T.);
+#2030=ADVANCED_FACE('',(#2029),#2023,.T.);
+#2036=EDGE_CURVE('',#1334,#1325,#647,.T.);
+#2042=ADVANCED_FACE('',(#2041),#2035,.T.);
+#2051=EDGE_CURVE('',#1338,#1340,#673,.T.);
+#2055=ADVANCED_FACE('',(#2054),#2047,.T.);
+#2061=EDGE_CURVE('',#1338,#1342,#690,.T.);
+#2064=EDGE_CURVE('',#1340,#1344,#797,.T.);
+#2066=EDGE_CURVE('',#1342,#1344,#683,.T.);
+#2070=ADVANCED_FACE('',(#2069),#2060,.T.);
+#2077=EDGE_CURVE('',#1352,#1342,#697,.T.);
+#2079=EDGE_CURVE('',#1356,#1352,#704,.T.);
+#2084=ADVANCED_FACE('',(#2083),#2075,.T.);
+#2090=EDGE_CURVE('',#1342,#1346,#711,.T.);
+#2092=EDGE_CURVE('',#1346,#1348,#718,.T.);
+#2094=EDGE_CURVE('',#1352,#1348,#725,.T.);
+#2099=ADVANCED_FACE('',(#2098),#2089,.T.);
+#2105=EDGE_CURVE('',#1344,#1318,#739,.T.);
+#2107=EDGE_CURVE('',#1318,#1346,#1176,.T.);
+#2113=ADVANCED_FACE('',(#2112),#2104,.T.);
+#2119=EDGE_CURVE('',#1317,#1318,#732,.T.);
+#2122=EDGE_CURVE('',#1344,#1448,#811,.T.);
+#2124=EDGE_CURVE('',#1448,#1317,#746,.T.);
+#2128=ADVANCED_FACE('',(#2127),#2118,.T.);
+#2135=EDGE_CURVE('',#1317,#1321,#770,.T.);
+#2137=EDGE_CURVE('',#1321,#1322,#946,.T.);
+#2139=EDGE_CURVE('',#1322,#1318,#1184,.T.);
+#2143=ADVANCED_FACE('',(#2142),#2133,.T.);
+#2149=EDGE_CURVE('',#1446,#1317,#754,.T.);
+#2151=EDGE_CURVE('',#1321,#1446,#762,.T.);
+#2156=ADVANCED_FACE('',(#2155),#2148,.T.);
+#2163=EDGE_CURVE('',#1450,#1448,#780,.T.);
+#2165=EDGE_CURVE('',#1450,#1446,#863,.T.);
+#2170=ADVANCED_FACE('',(#2169),#2161,.T.);
+#2176=EDGE_CURVE('',#1452,#1448,#804,.T.);
+#2179=EDGE_CURVE('',#1454,#1450,#832,.T.);
+#2184=ADVANCED_FACE('',(#2183),#2175,.T.);
+#2196=ADVANCED_FACE('',(#2195),#2189,.T.);
+#2202=EDGE_CURVE('',#1437,#1438,#818,.T.);
+#2204=EDGE_CURVE('',#1450,#1438,#825,.T.);
+#2210=ADVANCED_FACE('',(#2209),#2201,.T.);
+#2219=EDGE_CURVE('',#1442,#1438,#842,.T.);
+#2223=ADVANCED_FACE('',(#2222),#2215,.T.);
+#2229=EDGE_CURVE('',#1438,#1444,#849,.T.);
+#2233=EDGE_CURVE('',#1432,#1444,#879,.T.);
+#2237=ADVANCED_FACE('',(#2236),#2228,.T.);
+#2244=EDGE_CURVE('',#1444,#1446,#856,.T.);
+#2250=ADVANCED_FACE('',(#2249),#2242,.T.);
+#2257=EDGE_CURVE('',#1444,#1434,#871,.T.);
+#2259=EDGE_CURVE('',#1434,#1321,#953,.T.);
+#2264=ADVANCED_FACE('',(#2263),#2255,.T.);
+#2272=EDGE_CURVE('',#1434,#1432,#887,.T.);
+#2276=ADVANCED_FACE('',(#2275),#2269,.T.);
+#2283=EDGE_CURVE('',#1406,#1430,#895,.T.);
+#2285=EDGE_CURVE('',#1430,#1434,#960,.T.);
+#2290=ADVANCED_FACE('',(#2289),#2281,.T.);
+#2298=EDGE_CURVE('',#1430,#1410,#911,.T.);
+#2302=ADVANCED_FACE('',(#2301),#2295,.T.);
+#2308=EDGE_CURVE('',#1306,#1430,#967,.T.);
+#2312=EDGE_CURVE('',#1428,#1306,#996,.T.);
+#2316=ADVANCED_FACE('',(#2315),#2307,.T.);
+#2322=EDGE_CURVE('',#1305,#1306,#918,.T.);
+#2324=EDGE_CURVE('',#1314,#1305,#925,.T.);
+#2326=EDGE_CURVE('',#1313,#1314,#932,.T.);
+#2328=EDGE_CURVE('',#1322,#1313,#939,.T.);
+#2336=ADVANCED_FACE('',(#2335),#2321,.F.);
+#2342=EDGE_CURVE('',#1301,#1302,#974,.T.);
+#2344=EDGE_CURVE('',#1301,#1305,#1232,.T.);
+#2347=EDGE_CURVE('',#1306,#1302,#1012,.T.);
+#2351=ADVANCED_FACE('',(#2350),#2341,.T.);
+#2358=EDGE_CURVE('',#1426,#1302,#981,.T.);
+#2360=EDGE_CURVE('',#1426,#1382,#1026,.T.);
+#2362=EDGE_CURVE('',#1382,#1301,#988,.T.);
+#2366=ADVANCED_FACE('',(#2365),#2356,.T.);
+#2373=EDGE_CURVE('',#1302,#1428,#1004,.T.);
+#2379=ADVANCED_FACE('',(#2378),#2371,.T.);
+#2390=ADVANCED_FACE('',(#2389),#2384,.T.);
+#2396=EDGE_CURVE('',#1386,#1382,#1019,.T.);
+#2403=ADVANCED_FACE('',(#2402),#2395,.T.);
+#2411=EDGE_CURVE('',#1388,#1384,#1064,.T.);
+#2413=EDGE_CURVE('',#1384,#1382,#1242,.T.);
+#2417=ADVANCED_FACE('',(#2416),#2408,.T.);
+#2423=EDGE_CURVE('',#1370,#1374,#1050,.T.);
+#2425=EDGE_CURVE('',#1374,#1384,#1057,.T.);
+#2431=ADVANCED_FACE('',(#2430),#2422,.T.);
+#2439=EDGE_CURVE('',#1372,#1376,#1095,.T.);
+#2441=EDGE_CURVE('',#1374,#1376,#1074,.T.);
+#2445=ADVANCED_FACE('',(#2444),#2436,.T.);
+#2451=EDGE_CURVE('',#1354,#1350,#1081,.T.);
+#2453=EDGE_CURVE('',#1376,#1350,#1088,.T.);
+#2459=ADVANCED_FACE('',(#2458),#2450,.T.);
+#2468=EDGE_CURVE('',#1352,#1350,#1115,.T.);
+#2472=ADVANCED_FACE('',(#2471),#2464,.T.);
+#2478=EDGE_CURVE('',#1350,#1309,#1136,.T.);
+#2482=EDGE_CURVE('',#1348,#1309,#1144,.T.);
+#2486=ADVANCED_FACE('',(#2485),#2477,.T.);
+#2492=EDGE_CURVE('',#1309,#1310,#1122,.T.);
+#2494=EDGE_CURVE('',#1376,#1310,#1129,.T.);
+#2500=ADVANCED_FACE('',(#2499),#2491,.T.);
+#2507=EDGE_CURVE('',#1309,#1313,#1160,.T.);
+#2510=EDGE_CURVE('',#1314,#1310,#1208,.T.);
+#2514=ADVANCED_FACE('',(#2513),#2505,.T.);
+#2521=EDGE_CURVE('',#1313,#1348,#1152,.T.);
+#2526=ADVANCED_FACE('',(#2525),#2519,.T.);
+#2535=EDGE_CURVE('',#1346,#1322,#1168,.T.);
+#2539=ADVANCED_FACE('',(#2538),#2531,.T.);
+#2550=ADVANCED_FACE('',(#2549),#2544,.T.);
+#2556=EDGE_CURVE('',#1378,#1314,#1192,.T.);
+#2558=EDGE_CURVE('',#1310,#1378,#1200,.T.);
+#2563=ADVANCED_FACE('',(#2562),#2555,.T.);
+#2570=EDGE_CURVE('',#1305,#1380,#1224,.T.);
+#2572=EDGE_CURVE('',#1378,#1380,#1256,.T.);
+#2577=ADVANCED_FACE('',(#2576),#2568,.T.);
+#2583=EDGE_CURVE('',#1380,#1301,#1216,.T.);
+#2589=ADVANCED_FACE('',(#2588),#2582,.T.);
+#2597=EDGE_CURVE('',#1384,#1380,#1263,.T.);
+#2602=ADVANCED_FACE('',(#2601),#2594,.T.);
+#2608=EDGE_CURVE('',#1374,#1378,#1249,.T.);
+#2615=ADVANCED_FACE('',(#2614),#2607,.T.);
+#2627=ADVANCED_FACE('',(#2626),#2620,.T.);
+#2638=ADVANCED_FACE('',(#2637),#2632,.T.);
+#2647=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
+#2648=(NAMED_UNIT(*)PLANE_ANGLE_UNIT()SI_UNIT($,.RADIAN.));
+#2651=(NAMED_UNIT(*)SI_UNIT($,.STERADIAN.)SOLID_ANGLE_UNIT());
+#2653=(GEOMETRIC_REPRESENTATION_CONTEXT(3)GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((
+#2652))GLOBAL_UNIT_ASSIGNED_CONTEXT((#2647,#2650,#2651))REPRESENTATION_CONTEXT(
+'ID1','3'));
+#2657=AXIS2_PLACEMENT_3D('',#2654,#2655,#2656);
+#2658=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#2657,#2640),#2653);
+#2665=PRODUCT_DEFINITION('part definition','',#2664,#2661);
+#2666=PRODUCT_DEFINITION_SHAPE('','SHAPE FOR BODY-QFP.',#2665);
+#2667=SHAPE_ASPECT('','solid data associated with BODY-QFP',#2666,.F.);
+#2668=PROPERTY_DEFINITION('',
+'shape for solid data with which properties are associated',#2667);
+#2669=SHAPE_REPRESENTATION('',(#2640),#2653);
+#2670=SHAPE_DEFINITION_REPRESENTATION(#2668,#2669);
+#2671=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
+#2675=PROPERTY_DEFINITION('geometric validation property','area of BODY-QFP',
+#2667);
+#2676=REPRESENTATION('surface area',(#2674),#2653);
+#2677=PROPERTY_DEFINITION_REPRESENTATION(#2675,#2676);
+#2678=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
+#2682=PROPERTY_DEFINITION('geometric validation property','volume of BODY-QFP',
+#2667);
+#2683=REPRESENTATION('volume',(#2681),#2653);
+#2684=PROPERTY_DEFINITION_REPRESENTATION(#2682,#2683);
+#2686=PROPERTY_DEFINITION('geometric validation property',
+'centroid of BODY-QFP',#2667);
+#2687=REPRESENTATION('centroid',(#2685),#2653);
+#2688=PROPERTY_DEFINITION_REPRESENTATION(#2686,#2687);
+#2689=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
+#2693=PROPERTY_DEFINITION('geometric validation property','area of BODY-QFP',
+#2666);
+#2694=REPRESENTATION('surface area',(#2692),#2653);
+#2695=PROPERTY_DEFINITION_REPRESENTATION(#2693,#2694);
+#2696=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
+#2700=PROPERTY_DEFINITION('geometric validation property','volume of BODY-QFP',
+#2666);
+#2701=REPRESENTATION('volume',(#2699),#2653);
+#2702=PROPERTY_DEFINITION_REPRESENTATION(#2700,#2701);
+#2704=PROPERTY_DEFINITION('geometric validation property',
+'centroid of BODY-QFP',#2666);
+#2705=REPRESENTATION('centroid',(#2703),#2653);
+#2706=PROPERTY_DEFINITION_REPRESENTATION(#2704,#2705);
+#2707=SHAPE_DEFINITION_REPRESENTATION(#2666,#2658);
+#2708=PROPERTY_DEFINITION('BODY_Z','user defined attribute',#2665);
+#2712=REPRESENTATION('',(#2711),#2653);
+#2713=PROPERTY_DEFINITION_REPRESENTATION(#2708,#2712);
+#2715=REPRESENTATION('',(#2714),#2653);
+#2716=PROPERTY_DEFINITION('attribute type designation','Real Number',#2709);
+#2717=PROPERTY_DEFINITION_REPRESENTATION(#2716,#2715);
+#2718=SHAPE_DEFINITION_REPRESENTATION(#2719,#2720);
+#2719=PRODUCT_DEFINITION_SHAPE('','SHAPE FOR PM0064A_ASM.',#4177);
+#2720=SHAPE_REPRESENTATION('',(#2730,#3338,#3351,#3364,#3377,#3390,#3403,#3416,
+#3429,#3442,#3455,#3468,#3481,#3494,#3507,#3520,#3533,#3546,#3559,#3572,#3585,
+#3598,#3611,#3624,#3637,#3650,#3663,#3676,#3689,#3702,#3715,#3728,#3741,#3754,
+#3767,#3780,#3793,#3806,#3819,#3832,#3845,#3858,#3871,#3884,#3897,#3910,#3923,
+#3936,#3949,#3962,#3975,#3988,#4001,#4014,#4027,#4040,#4053,#4066,#4079,#4092,
+#4105,#4118,#4131,#4144,#4157,#4171),#4167);
+#2721=NEXT_ASSEMBLY_USAGE_OCCURRENCE('0','Next assembly relationship',
+'BODY-QFP',#4177,#2665,$);
+#2722=PRODUCT_DEFINITION_SHAPE('Placement #0',
+'Placement of BODY-QFP with respect to PM0064A_ASM',#2721);
+#2724=PROPERTY_DEFINITION('geometric validation property',
+'centroid of BODY-QFP',#2722);
+#2725=REPRESENTATION('centroid',(#2723),#2653);
+#2726=PROPERTY_DEFINITION_REPRESENTATION(#2724,#2725);
+#2858=CIRCLE('',#2857,2.1E-1);
+#2873=CIRCLE('',#2872,2.1E-1);
+#2902=CIRCLE('',#2901,8.E-2);
+#2917=CIRCLE('',#2916,8.E-2);
+#2932=CIRCLE('',#2931,8.E-2);
+#2947=CIRCLE('',#2946,8.E-2);
+#2976=CIRCLE('',#2975,2.1E-1);
+#2991=CIRCLE('',#2990,2.1E-1);
+#3048=EDGE_CURVE('',#3017,#3037,#2787,.T.);
+#3050=EDGE_CURVE('',#3013,#3017,#2902,.T.);
+#3052=EDGE_CURVE('',#3013,#3005,#2738,.T.);
+#3054=EDGE_CURVE('',#3005,#3006,#2745,.T.);
+#3056=EDGE_CURVE('',#3006,#3025,#2752,.T.);
+#3058=EDGE_CURVE('',#3021,#3025,#2858,.T.);
+#3060=EDGE_CURVE('',#3033,#3021,#2836,.T.);
+#3062=EDGE_CURVE('',#3029,#3033,#2932,.T.);
+#3064=EDGE_CURVE('',#3029,#2997,#2759,.T.);
+#3066=EDGE_CURVE('',#2997,#2998,#2766,.T.);
+#3068=EDGE_CURVE('',#2998,#3041,#2773,.T.);
+#3070=EDGE_CURVE('',#3037,#3041,#2976,.T.);
+#3074=ADVANCED_FACE('',(#3073),#3047,.F.);
+#3080=EDGE_CURVE('',#3038,#3018,#2780,.T.);
+#3082=EDGE_CURVE('',#3017,#3018,#2909,.T.);
+#3085=EDGE_CURVE('',#3037,#3038,#2968,.T.);
+#3089=ADVANCED_FACE('',(#3088),#3079,.T.);
+#3095=EDGE_CURVE('',#3022,#3034,#2843,.T.);
+#3097=EDGE_CURVE('',#3022,#3026,#2873,.T.);
+#3099=EDGE_CURVE('',#3010,#3026,#2794,.T.);
+#3101=EDGE_CURVE('',#3009,#3010,#2801,.T.);
+#3103=EDGE_CURVE('',#3014,#3009,#2808,.T.);
+#3105=EDGE_CURVE('',#3014,#3018,#2917,.T.);
+#3108=EDGE_CURVE('',#3038,#3042,#2991,.T.);
+#3110=EDGE_CURVE('',#3002,#3042,#2815,.T.);
+#3112=EDGE_CURVE('',#3001,#3002,#2822,.T.);
+#3114=EDGE_CURVE('',#3030,#3001,#2829,.T.);
+#3116=EDGE_CURVE('',#3030,#3034,#2947,.T.);
+#3120=ADVANCED_FACE('',(#3119),#3094,.T.);
+#3127=EDGE_CURVE('',#3021,#3022,#2850,.T.);
+#3130=EDGE_CURVE('',#3033,#3034,#2939,.T.);
+#3134=ADVANCED_FACE('',(#3133),#3125,.T.);
+#3142=EDGE_CURVE('',#3025,#3026,#2865,.T.);
+#3147=ADVANCED_FACE('',(#3146),#3139,.T.);
+#3154=EDGE_CURVE('',#3006,#3010,#2880,.T.);
+#3160=ADVANCED_FACE('',(#3159),#3152,.T.);
+#3167=EDGE_CURVE('',#3005,#3009,#2887,.T.);
+#3173=ADVANCED_FACE('',(#3172),#3165,.T.);
+#3180=EDGE_CURVE('',#3013,#3014,#2894,.T.);
+#3186=ADVANCED_FACE('',(#3185),#3178,.T.);
+#3198=ADVANCED_FACE('',(#3197),#3191,.F.);
+#3204=EDGE_CURVE('',#3029,#3030,#2924,.T.);
+#3211=ADVANCED_FACE('',(#3210),#3203,.F.);
+#3220=EDGE_CURVE('',#2997,#3001,#2954,.T.);
+#3224=ADVANCED_FACE('',(#3223),#3216,.T.);
+#3233=EDGE_CURVE('',#2998,#3002,#2961,.T.);
+#3237=ADVANCED_FACE('',(#3236),#3229,.T.);
+#3246=EDGE_CURVE('',#3041,#3042,#2983,.T.);
+#3250=ADVANCED_FACE('',(#3249),#3242,.T.);
+#3262=ADVANCED_FACE('',(#3261),#3255,.T.);
+#3271=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
+#3272=(NAMED_UNIT(*)PLANE_ANGLE_UNIT()SI_UNIT($,.RADIAN.));
+#3275=(NAMED_UNIT(*)SI_UNIT($,.STERADIAN.)SOLID_ANGLE_UNIT());
+#3277=(GEOMETRIC_REPRESENTATION_CONTEXT(3)GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((
+#3276))GLOBAL_UNIT_ASSIGNED_CONTEXT((#3271,#3274,#3275))REPRESENTATION_CONTEXT(
+'ID2','3'));
+#3281=AXIS2_PLACEMENT_3D('',#3278,#3279,#3280);
+#3282=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#3281,#3264),#3277);
+#3286=PRODUCT_DEFINITION('part definition','',#3285,#2661);
+#3287=PRODUCT_DEFINITION_SHAPE('','SHAPE FOR LEAD-QFP.',#3286);
+#3288=SHAPE_ASPECT('','solid data associated with LEAD-QFP',#3287,.F.);
+#3289=PROPERTY_DEFINITION('',
+'shape for solid data with which properties are associated',#3288);
+#3290=SHAPE_REPRESENTATION('',(#3264),#3277);
+#3291=SHAPE_DEFINITION_REPRESENTATION(#3289,#3290);
+#3292=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
+#3296=PROPERTY_DEFINITION('geometric validation property','area of LEAD-QFP',
+#3288);
+#3297=REPRESENTATION('surface area',(#3295),#3277);
+#3298=PROPERTY_DEFINITION_REPRESENTATION(#3296,#3297);
+#3299=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
+#3303=PROPERTY_DEFINITION('geometric validation property','volume of LEAD-QFP',
+#3288);
+#3304=REPRESENTATION('volume',(#3302),#3277);
+#3305=PROPERTY_DEFINITION_REPRESENTATION(#3303,#3304);
+#3307=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3288);
+#3308=REPRESENTATION('centroid',(#3306),#3277);
+#3309=PROPERTY_DEFINITION_REPRESENTATION(#3307,#3308);
+#3310=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
+#3314=PROPERTY_DEFINITION('geometric validation property','area of LEAD-QFP',
+#3287);
+#3315=REPRESENTATION('surface area',(#3313),#3277);
+#3316=PROPERTY_DEFINITION_REPRESENTATION(#3314,#3315);
+#3317=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
+#3321=PROPERTY_DEFINITION('geometric validation property','volume of LEAD-QFP',
+#3287);
+#3322=REPRESENTATION('volume',(#3320),#3277);
+#3323=PROPERTY_DEFINITION_REPRESENTATION(#3321,#3322);
+#3325=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3287);
+#3326=REPRESENTATION('centroid',(#3324),#3277);
+#3327=PROPERTY_DEFINITION_REPRESENTATION(#3325,#3326);
+#3328=SHAPE_DEFINITION_REPRESENTATION(#3287,#3282);
+#3329=NEXT_ASSEMBLY_USAGE_OCCURRENCE('1','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3330=PRODUCT_DEFINITION_SHAPE('Placement #1',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3329);
+#3332=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3330);
+#3333=REPRESENTATION('centroid',(#3331),#3277);
+#3334=PROPERTY_DEFINITION_REPRESENTATION(#3332,#3333);
+#3342=NEXT_ASSEMBLY_USAGE_OCCURRENCE('2','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3343=PRODUCT_DEFINITION_SHAPE('Placement #2',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3342);
+#3345=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3343);
+#3346=REPRESENTATION('centroid',(#3344),#3277);
+#3347=PROPERTY_DEFINITION_REPRESENTATION(#3345,#3346);
+#3355=NEXT_ASSEMBLY_USAGE_OCCURRENCE('3','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3356=PRODUCT_DEFINITION_SHAPE('Placement #3',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3355);
+#3358=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3356);
+#3359=REPRESENTATION('centroid',(#3357),#3277);
+#3360=PROPERTY_DEFINITION_REPRESENTATION(#3358,#3359);
+#3368=NEXT_ASSEMBLY_USAGE_OCCURRENCE('4','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3369=PRODUCT_DEFINITION_SHAPE('Placement #4',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3368);
+#3371=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3369);
+#3372=REPRESENTATION('centroid',(#3370),#3277);
+#3373=PROPERTY_DEFINITION_REPRESENTATION(#3371,#3372);
+#3381=NEXT_ASSEMBLY_USAGE_OCCURRENCE('5','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3382=PRODUCT_DEFINITION_SHAPE('Placement #5',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3381);
+#3384=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3382);
+#3385=REPRESENTATION('centroid',(#3383),#3277);
+#3386=PROPERTY_DEFINITION_REPRESENTATION(#3384,#3385);
+#3394=NEXT_ASSEMBLY_USAGE_OCCURRENCE('6','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3395=PRODUCT_DEFINITION_SHAPE('Placement #6',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3394);
+#3397=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3395);
+#3398=REPRESENTATION('centroid',(#3396),#3277);
+#3399=PROPERTY_DEFINITION_REPRESENTATION(#3397,#3398);
+#3407=NEXT_ASSEMBLY_USAGE_OCCURRENCE('7','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3408=PRODUCT_DEFINITION_SHAPE('Placement #7',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3407);
+#3410=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3408);
+#3411=REPRESENTATION('centroid',(#3409),#3277);
+#3412=PROPERTY_DEFINITION_REPRESENTATION(#3410,#3411);
+#3420=NEXT_ASSEMBLY_USAGE_OCCURRENCE('8','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3421=PRODUCT_DEFINITION_SHAPE('Placement #8',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3420);
+#3423=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3421);
+#3424=REPRESENTATION('centroid',(#3422),#3277);
+#3425=PROPERTY_DEFINITION_REPRESENTATION(#3423,#3424);
+#3433=NEXT_ASSEMBLY_USAGE_OCCURRENCE('9','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3434=PRODUCT_DEFINITION_SHAPE('Placement #9',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3433);
+#3436=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3434);
+#3437=REPRESENTATION('centroid',(#3435),#3277);
+#3438=PROPERTY_DEFINITION_REPRESENTATION(#3436,#3437);
+#3446=NEXT_ASSEMBLY_USAGE_OCCURRENCE('10','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3447=PRODUCT_DEFINITION_SHAPE('Placement #10',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3446);
+#3449=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3447);
+#3450=REPRESENTATION('centroid',(#3448),#3277);
+#3451=PROPERTY_DEFINITION_REPRESENTATION(#3449,#3450);
+#3459=NEXT_ASSEMBLY_USAGE_OCCURRENCE('11','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3460=PRODUCT_DEFINITION_SHAPE('Placement #11',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3459);
+#3462=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3460);
+#3463=REPRESENTATION('centroid',(#3461),#3277);
+#3464=PROPERTY_DEFINITION_REPRESENTATION(#3462,#3463);
+#3472=NEXT_ASSEMBLY_USAGE_OCCURRENCE('12','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3473=PRODUCT_DEFINITION_SHAPE('Placement #12',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3472);
+#3475=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3473);
+#3476=REPRESENTATION('centroid',(#3474),#3277);
+#3477=PROPERTY_DEFINITION_REPRESENTATION(#3475,#3476);
+#3485=NEXT_ASSEMBLY_USAGE_OCCURRENCE('13','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3486=PRODUCT_DEFINITION_SHAPE('Placement #13',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3485);
+#3488=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3486);
+#3489=REPRESENTATION('centroid',(#3487),#3277);
+#3490=PROPERTY_DEFINITION_REPRESENTATION(#3488,#3489);
+#3498=NEXT_ASSEMBLY_USAGE_OCCURRENCE('14','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3499=PRODUCT_DEFINITION_SHAPE('Placement #14',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3498);
+#3501=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3499);
+#3502=REPRESENTATION('centroid',(#3500),#3277);
+#3503=PROPERTY_DEFINITION_REPRESENTATION(#3501,#3502);
+#3511=NEXT_ASSEMBLY_USAGE_OCCURRENCE('15','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3512=PRODUCT_DEFINITION_SHAPE('Placement #15',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3511);
+#3514=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3512);
+#3515=REPRESENTATION('centroid',(#3513),#3277);
+#3516=PROPERTY_DEFINITION_REPRESENTATION(#3514,#3515);
+#3524=NEXT_ASSEMBLY_USAGE_OCCURRENCE('16','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3525=PRODUCT_DEFINITION_SHAPE('Placement #16',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3524);
+#3527=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3525);
+#3528=REPRESENTATION('centroid',(#3526),#3277);
+#3529=PROPERTY_DEFINITION_REPRESENTATION(#3527,#3528);
+#3537=NEXT_ASSEMBLY_USAGE_OCCURRENCE('17','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3538=PRODUCT_DEFINITION_SHAPE('Placement #17',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3537);
+#3540=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3538);
+#3541=REPRESENTATION('centroid',(#3539),#3277);
+#3542=PROPERTY_DEFINITION_REPRESENTATION(#3540,#3541);
+#3550=NEXT_ASSEMBLY_USAGE_OCCURRENCE('18','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3551=PRODUCT_DEFINITION_SHAPE('Placement #18',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3550);
+#3553=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3551);
+#3554=REPRESENTATION('centroid',(#3552),#3277);
+#3555=PROPERTY_DEFINITION_REPRESENTATION(#3553,#3554);
+#3563=NEXT_ASSEMBLY_USAGE_OCCURRENCE('19','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3564=PRODUCT_DEFINITION_SHAPE('Placement #19',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3563);
+#3566=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3564);
+#3567=REPRESENTATION('centroid',(#3565),#3277);
+#3568=PROPERTY_DEFINITION_REPRESENTATION(#3566,#3567);
+#3576=NEXT_ASSEMBLY_USAGE_OCCURRENCE('20','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3577=PRODUCT_DEFINITION_SHAPE('Placement #20',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3576);
+#3579=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3577);
+#3580=REPRESENTATION('centroid',(#3578),#3277);
+#3581=PROPERTY_DEFINITION_REPRESENTATION(#3579,#3580);
+#3589=NEXT_ASSEMBLY_USAGE_OCCURRENCE('21','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3590=PRODUCT_DEFINITION_SHAPE('Placement #21',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3589);
+#3592=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3590);
+#3593=REPRESENTATION('centroid',(#3591),#3277);
+#3594=PROPERTY_DEFINITION_REPRESENTATION(#3592,#3593);
+#3602=NEXT_ASSEMBLY_USAGE_OCCURRENCE('22','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3603=PRODUCT_DEFINITION_SHAPE('Placement #22',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3602);
+#3605=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3603);
+#3606=REPRESENTATION('centroid',(#3604),#3277);
+#3607=PROPERTY_DEFINITION_REPRESENTATION(#3605,#3606);
+#3615=NEXT_ASSEMBLY_USAGE_OCCURRENCE('23','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3616=PRODUCT_DEFINITION_SHAPE('Placement #23',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3615);
+#3618=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3616);
+#3619=REPRESENTATION('centroid',(#3617),#3277);
+#3620=PROPERTY_DEFINITION_REPRESENTATION(#3618,#3619);
+#3628=NEXT_ASSEMBLY_USAGE_OCCURRENCE('24','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3629=PRODUCT_DEFINITION_SHAPE('Placement #24',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3628);
+#3631=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3629);
+#3632=REPRESENTATION('centroid',(#3630),#3277);
+#3633=PROPERTY_DEFINITION_REPRESENTATION(#3631,#3632);
+#3641=NEXT_ASSEMBLY_USAGE_OCCURRENCE('25','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3642=PRODUCT_DEFINITION_SHAPE('Placement #25',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3641);
+#3644=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3642);
+#3645=REPRESENTATION('centroid',(#3643),#3277);
+#3646=PROPERTY_DEFINITION_REPRESENTATION(#3644,#3645);
+#3654=NEXT_ASSEMBLY_USAGE_OCCURRENCE('26','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3655=PRODUCT_DEFINITION_SHAPE('Placement #26',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3654);
+#3657=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3655);
+#3658=REPRESENTATION('centroid',(#3656),#3277);
+#3659=PROPERTY_DEFINITION_REPRESENTATION(#3657,#3658);
+#3667=NEXT_ASSEMBLY_USAGE_OCCURRENCE('27','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3668=PRODUCT_DEFINITION_SHAPE('Placement #27',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3667);
+#3670=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3668);
+#3671=REPRESENTATION('centroid',(#3669),#3277);
+#3672=PROPERTY_DEFINITION_REPRESENTATION(#3670,#3671);
+#3680=NEXT_ASSEMBLY_USAGE_OCCURRENCE('28','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3681=PRODUCT_DEFINITION_SHAPE('Placement #28',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3680);
+#3683=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3681);
+#3684=REPRESENTATION('centroid',(#3682),#3277);
+#3685=PROPERTY_DEFINITION_REPRESENTATION(#3683,#3684);
+#3693=NEXT_ASSEMBLY_USAGE_OCCURRENCE('29','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3694=PRODUCT_DEFINITION_SHAPE('Placement #29',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3693);
+#3696=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3694);
+#3697=REPRESENTATION('centroid',(#3695),#3277);
+#3698=PROPERTY_DEFINITION_REPRESENTATION(#3696,#3697);
+#3706=NEXT_ASSEMBLY_USAGE_OCCURRENCE('30','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3707=PRODUCT_DEFINITION_SHAPE('Placement #30',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3706);
+#3709=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3707);
+#3710=REPRESENTATION('centroid',(#3708),#3277);
+#3711=PROPERTY_DEFINITION_REPRESENTATION(#3709,#3710);
+#3719=NEXT_ASSEMBLY_USAGE_OCCURRENCE('31','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3720=PRODUCT_DEFINITION_SHAPE('Placement #31',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3719);
+#3722=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3720);
+#3723=REPRESENTATION('centroid',(#3721),#3277);
+#3724=PROPERTY_DEFINITION_REPRESENTATION(#3722,#3723);
+#3732=NEXT_ASSEMBLY_USAGE_OCCURRENCE('32','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3733=PRODUCT_DEFINITION_SHAPE('Placement #32',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3732);
+#3735=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3733);
+#3736=REPRESENTATION('centroid',(#3734),#3277);
+#3737=PROPERTY_DEFINITION_REPRESENTATION(#3735,#3736);
+#3745=NEXT_ASSEMBLY_USAGE_OCCURRENCE('33','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3746=PRODUCT_DEFINITION_SHAPE('Placement #33',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3745);
+#3748=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3746);
+#3749=REPRESENTATION('centroid',(#3747),#3277);
+#3750=PROPERTY_DEFINITION_REPRESENTATION(#3748,#3749);
+#3758=NEXT_ASSEMBLY_USAGE_OCCURRENCE('34','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3759=PRODUCT_DEFINITION_SHAPE('Placement #34',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3758);
+#3761=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3759);
+#3762=REPRESENTATION('centroid',(#3760),#3277);
+#3763=PROPERTY_DEFINITION_REPRESENTATION(#3761,#3762);
+#3771=NEXT_ASSEMBLY_USAGE_OCCURRENCE('35','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3772=PRODUCT_DEFINITION_SHAPE('Placement #35',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3771);
+#3774=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3772);
+#3775=REPRESENTATION('centroid',(#3773),#3277);
+#3776=PROPERTY_DEFINITION_REPRESENTATION(#3774,#3775);
+#3784=NEXT_ASSEMBLY_USAGE_OCCURRENCE('36','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3785=PRODUCT_DEFINITION_SHAPE('Placement #36',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3784);
+#3787=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3785);
+#3788=REPRESENTATION('centroid',(#3786),#3277);
+#3789=PROPERTY_DEFINITION_REPRESENTATION(#3787,#3788);
+#3797=NEXT_ASSEMBLY_USAGE_OCCURRENCE('37','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3798=PRODUCT_DEFINITION_SHAPE('Placement #37',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3797);
+#3800=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3798);
+#3801=REPRESENTATION('centroid',(#3799),#3277);
+#3802=PROPERTY_DEFINITION_REPRESENTATION(#3800,#3801);
+#3810=NEXT_ASSEMBLY_USAGE_OCCURRENCE('38','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3811=PRODUCT_DEFINITION_SHAPE('Placement #38',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3810);
+#3813=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3811);
+#3814=REPRESENTATION('centroid',(#3812),#3277);
+#3815=PROPERTY_DEFINITION_REPRESENTATION(#3813,#3814);
+#3823=NEXT_ASSEMBLY_USAGE_OCCURRENCE('39','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3824=PRODUCT_DEFINITION_SHAPE('Placement #39',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3823);
+#3826=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3824);
+#3827=REPRESENTATION('centroid',(#3825),#3277);
+#3828=PROPERTY_DEFINITION_REPRESENTATION(#3826,#3827);
+#3836=NEXT_ASSEMBLY_USAGE_OCCURRENCE('40','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3837=PRODUCT_DEFINITION_SHAPE('Placement #40',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3836);
+#3839=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3837);
+#3840=REPRESENTATION('centroid',(#3838),#3277);
+#3841=PROPERTY_DEFINITION_REPRESENTATION(#3839,#3840);
+#3849=NEXT_ASSEMBLY_USAGE_OCCURRENCE('41','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3850=PRODUCT_DEFINITION_SHAPE('Placement #41',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3849);
+#3852=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3850);
+#3853=REPRESENTATION('centroid',(#3851),#3277);
+#3854=PROPERTY_DEFINITION_REPRESENTATION(#3852,#3853);
+#3862=NEXT_ASSEMBLY_USAGE_OCCURRENCE('42','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3863=PRODUCT_DEFINITION_SHAPE('Placement #42',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3862);
+#3865=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3863);
+#3866=REPRESENTATION('centroid',(#3864),#3277);
+#3867=PROPERTY_DEFINITION_REPRESENTATION(#3865,#3866);
+#3875=NEXT_ASSEMBLY_USAGE_OCCURRENCE('43','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3876=PRODUCT_DEFINITION_SHAPE('Placement #43',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3875);
+#3878=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3876);
+#3879=REPRESENTATION('centroid',(#3877),#3277);
+#3880=PROPERTY_DEFINITION_REPRESENTATION(#3878,#3879);
+#3888=NEXT_ASSEMBLY_USAGE_OCCURRENCE('44','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3889=PRODUCT_DEFINITION_SHAPE('Placement #44',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3888);
+#3891=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3889);
+#3892=REPRESENTATION('centroid',(#3890),#3277);
+#3893=PROPERTY_DEFINITION_REPRESENTATION(#3891,#3892);
+#3901=NEXT_ASSEMBLY_USAGE_OCCURRENCE('45','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3902=PRODUCT_DEFINITION_SHAPE('Placement #45',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3901);
+#3904=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3902);
+#3905=REPRESENTATION('centroid',(#3903),#3277);
+#3906=PROPERTY_DEFINITION_REPRESENTATION(#3904,#3905);
+#3914=NEXT_ASSEMBLY_USAGE_OCCURRENCE('46','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3915=PRODUCT_DEFINITION_SHAPE('Placement #46',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3914);
+#3917=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3915);
+#3918=REPRESENTATION('centroid',(#3916),#3277);
+#3919=PROPERTY_DEFINITION_REPRESENTATION(#3917,#3918);
+#3927=NEXT_ASSEMBLY_USAGE_OCCURRENCE('47','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3928=PRODUCT_DEFINITION_SHAPE('Placement #47',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3927);
+#3930=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3928);
+#3931=REPRESENTATION('centroid',(#3929),#3277);
+#3932=PROPERTY_DEFINITION_REPRESENTATION(#3930,#3931);
+#3940=NEXT_ASSEMBLY_USAGE_OCCURRENCE('48','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3941=PRODUCT_DEFINITION_SHAPE('Placement #48',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3940);
+#3943=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3941);
+#3944=REPRESENTATION('centroid',(#3942),#3277);
+#3945=PROPERTY_DEFINITION_REPRESENTATION(#3943,#3944);
+#3953=NEXT_ASSEMBLY_USAGE_OCCURRENCE('49','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3954=PRODUCT_DEFINITION_SHAPE('Placement #49',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3953);
+#3956=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3954);
+#3957=REPRESENTATION('centroid',(#3955),#3277);
+#3958=PROPERTY_DEFINITION_REPRESENTATION(#3956,#3957);
+#3966=NEXT_ASSEMBLY_USAGE_OCCURRENCE('50','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3967=PRODUCT_DEFINITION_SHAPE('Placement #50',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3966);
+#3969=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3967);
+#3970=REPRESENTATION('centroid',(#3968),#3277);
+#3971=PROPERTY_DEFINITION_REPRESENTATION(#3969,#3970);
+#3979=NEXT_ASSEMBLY_USAGE_OCCURRENCE('51','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3980=PRODUCT_DEFINITION_SHAPE('Placement #51',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3979);
+#3982=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3980);
+#3983=REPRESENTATION('centroid',(#3981),#3277);
+#3984=PROPERTY_DEFINITION_REPRESENTATION(#3982,#3983);
+#3992=NEXT_ASSEMBLY_USAGE_OCCURRENCE('52','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#3993=PRODUCT_DEFINITION_SHAPE('Placement #52',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#3992);
+#3995=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#3993);
+#3996=REPRESENTATION('centroid',(#3994),#3277);
+#3997=PROPERTY_DEFINITION_REPRESENTATION(#3995,#3996);
+#4005=NEXT_ASSEMBLY_USAGE_OCCURRENCE('53','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#4006=PRODUCT_DEFINITION_SHAPE('Placement #53',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#4005);
+#4008=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#4006);
+#4009=REPRESENTATION('centroid',(#4007),#3277);
+#4010=PROPERTY_DEFINITION_REPRESENTATION(#4008,#4009);
+#4018=NEXT_ASSEMBLY_USAGE_OCCURRENCE('54','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#4019=PRODUCT_DEFINITION_SHAPE('Placement #54',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#4018);
+#4021=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#4019);
+#4022=REPRESENTATION('centroid',(#4020),#3277);
+#4023=PROPERTY_DEFINITION_REPRESENTATION(#4021,#4022);
+#4031=NEXT_ASSEMBLY_USAGE_OCCURRENCE('55','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#4032=PRODUCT_DEFINITION_SHAPE('Placement #55',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#4031);
+#4034=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#4032);
+#4035=REPRESENTATION('centroid',(#4033),#3277);
+#4036=PROPERTY_DEFINITION_REPRESENTATION(#4034,#4035);
+#4044=NEXT_ASSEMBLY_USAGE_OCCURRENCE('56','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#4045=PRODUCT_DEFINITION_SHAPE('Placement #56',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#4044);
+#4047=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#4045);
+#4048=REPRESENTATION('centroid',(#4046),#3277);
+#4049=PROPERTY_DEFINITION_REPRESENTATION(#4047,#4048);
+#4057=NEXT_ASSEMBLY_USAGE_OCCURRENCE('57','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#4058=PRODUCT_DEFINITION_SHAPE('Placement #57',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#4057);
+#4060=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#4058);
+#4061=REPRESENTATION('centroid',(#4059),#3277);
+#4062=PROPERTY_DEFINITION_REPRESENTATION(#4060,#4061);
+#4070=NEXT_ASSEMBLY_USAGE_OCCURRENCE('58','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#4071=PRODUCT_DEFINITION_SHAPE('Placement #58',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#4070);
+#4073=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#4071);
+#4074=REPRESENTATION('centroid',(#4072),#3277);
+#4075=PROPERTY_DEFINITION_REPRESENTATION(#4073,#4074);
+#4083=NEXT_ASSEMBLY_USAGE_OCCURRENCE('59','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#4084=PRODUCT_DEFINITION_SHAPE('Placement #59',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#4083);
+#4086=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#4084);
+#4087=REPRESENTATION('centroid',(#4085),#3277);
+#4088=PROPERTY_DEFINITION_REPRESENTATION(#4086,#4087);
+#4096=NEXT_ASSEMBLY_USAGE_OCCURRENCE('60','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#4097=PRODUCT_DEFINITION_SHAPE('Placement #60',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#4096);
+#4099=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#4097);
+#4100=REPRESENTATION('centroid',(#4098),#3277);
+#4101=PROPERTY_DEFINITION_REPRESENTATION(#4099,#4100);
+#4109=NEXT_ASSEMBLY_USAGE_OCCURRENCE('61','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#4110=PRODUCT_DEFINITION_SHAPE('Placement #61',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#4109);
+#4112=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#4110);
+#4113=REPRESENTATION('centroid',(#4111),#3277);
+#4114=PROPERTY_DEFINITION_REPRESENTATION(#4112,#4113);
+#4122=NEXT_ASSEMBLY_USAGE_OCCURRENCE('62','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#4123=PRODUCT_DEFINITION_SHAPE('Placement #62',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#4122);
+#4125=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#4123);
+#4126=REPRESENTATION('centroid',(#4124),#3277);
+#4127=PROPERTY_DEFINITION_REPRESENTATION(#4125,#4126);
+#4135=NEXT_ASSEMBLY_USAGE_OCCURRENCE('63','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#4136=PRODUCT_DEFINITION_SHAPE('Placement #63',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#4135);
+#4138=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#4136);
+#4139=REPRESENTATION('centroid',(#4137),#3277);
+#4140=PROPERTY_DEFINITION_REPRESENTATION(#4138,#4139);
+#4148=NEXT_ASSEMBLY_USAGE_OCCURRENCE('64','Next assembly relationship',
+'LEAD-QFP',#4177,#3286,$);
+#4149=PRODUCT_DEFINITION_SHAPE('Placement #64',
+'Placement of LEAD-QFP with respect to PM0064A_ASM',#4148);
+#4151=PROPERTY_DEFINITION('geometric validation property',
+'centroid of LEAD-QFP',#4149);
+#4152=REPRESENTATION('centroid',(#4150),#3277);
+#4153=PROPERTY_DEFINITION_REPRESENTATION(#4151,#4152);
+#4161=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
+#4162=(NAMED_UNIT(*)PLANE_ANGLE_UNIT()SI_UNIT($,.RADIAN.));
+#4165=(NAMED_UNIT(*)SI_UNIT($,.STERADIAN.)SOLID_ANGLE_UNIT());
+#4167=(GEOMETRIC_REPRESENTATION_CONTEXT(3)GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((
+#4166))GLOBAL_UNIT_ASSIGNED_CONTEXT((#4161,#4164,#4165))REPRESENTATION_CONTEXT(
+'ID3','3'));
+#4171=AXIS2_PLACEMENT_3D('',#4168,#4169,#4170);
+#4177=PRODUCT_DEFINITION('part definition','',#4176,#4173);
+#4178=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
+#4182=PROPERTY_DEFINITION('geometric validation property','area of PM0064A_ASM',
+#2719);
+#4183=REPRESENTATION('surface area',(#4181),#4167);
+#4184=PROPERTY_DEFINITION_REPRESENTATION(#4182,#4183);
+#4185=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
+#4189=PROPERTY_DEFINITION('geometric validation property',
+'volume of PM0064A_ASM',#2719);
+#4190=REPRESENTATION('volume',(#4188),#4167);
+#4191=PROPERTY_DEFINITION_REPRESENTATION(#4189,#4190);
+#4193=PROPERTY_DEFINITION('geometric validation property',
+'centroid of PM0064A_ASM',#2719);
+#4194=REPRESENTATION('centroid',(#4192),#4167);
+#4195=PROPERTY_DEFINITION_REPRESENTATION(#4193,#4194);
+#4197=PROPERTY_DEFINITION('AUTHOR','user defined attribute',#4177);
+#4201=REPRESENTATION('',(#4200),#4167);
+#4202=PROPERTY_DEFINITION_REPRESENTATION(#4197,#4201);
+#4203=PROPERTY_DEFINITION('DATE','user defined attribute',#4177);
+#4207=REPRESENTATION('',(#4206),#4167);
+#4208=PROPERTY_DEFINITION_REPRESENTATION(#4203,#4207);
+#4209=PROPERTY_DEFINITION('DWG_NO','user defined attribute',#4177);
+#4213=REPRESENTATION('',(#4212),#4167);
+#4214=PROPERTY_DEFINITION_REPRESENTATION(#4209,#4213);
+#4215=PROPERTY_DEFINITION('REV','user defined attribute',#4177);
+#4219=REPRESENTATION('',(#4218),#4167);
+#4220=PROPERTY_DEFINITION_REPRESENTATION(#4215,#4219);
+#4221=PROPERTY_DEFINITION('TITLE','user defined attribute',#4177);
+#4224=PROPERTY_DEFINITION('DCHK','user defined attribute',#4177);
+#4228=REPRESENTATION('',(#4227),#4167);
+#4229=PROPERTY_DEFINITION_REPRESENTATION(#4224,#4228);
+#4230=PROPERTY_DEFINITION('DCHK_DATE','user defined attribute',#4177);
+#4234=REPRESENTATION('',(#4233),#4167);
+#4235=PROPERTY_DEFINITION_REPRESENTATION(#4230,#4234);
+#4236=PROPERTY_DEFINITION('ECHK','user defined attribute',#4177);
+#4240=REPRESENTATION('',(#4239),#4167);
+#4241=PROPERTY_DEFINITION_REPRESENTATION(#4236,#4240);
+#4242=PROPERTY_DEFINITION('ECHK_DATE','user defined attribute',#4177);
+#4246=REPRESENTATION('',(#4245),#4167);
+#4247=PROPERTY_DEFINITION_REPRESENTATION(#4242,#4246);
+#4248=PROPERTY_DEFINITION('LD_PITCH','user defined attribute',#4177);
+#4252=REPRESENTATION('',(#4251),#4167);
+#4253=PROPERTY_DEFINITION_REPRESENTATION(#4248,#4252);
+#4255=REPRESENTATION('',(#4254),#4167);
+#4256=PROPERTY_DEFINITION('attribute type designation','Real Number',#4249);
+#4257=PROPERTY_DEFINITION_REPRESENTATION(#4256,#4255);
+#4258=PROPERTY_DEFINITION('RELEASED','user defined attribute',#4177);
+#4262=REPRESENTATION('',(#4261),#4167);
+#4263=PROPERTY_DEFINITION_REPRESENTATION(#4258,#4262);
+#4264=PROPERTY_DEFINITION('REL_DATE','user defined attribute',#4177);
+#4268=REPRESENTATION('',(#4267),#4167);
+#4269=PROPERTY_DEFINITION_REPRESENTATION(#4264,#4268);
+#4270=PROPERTY_DEFINITION('DESIGNER','user defined attribute',#4177);
+#4274=REPRESENTATION('',(#4273),#4167);
+#4275=PROPERTY_DEFINITION_REPRESENTATION(#4270,#4274);
+#4276=PROPERTY_DEFINITION('DES_DATE','user defined attribute',#4177);
+#4280=REPRESENTATION('',(#4279),#4167);
+#4281=PROPERTY_DEFINITION_REPRESENTATION(#4276,#4280);
+#4282=PROPERTY_DEFINITION('APPROVER','user defined attribute',#4177);
+#4286=REPRESENTATION('',(#4285),#4167);
+#4287=PROPERTY_DEFINITION_REPRESENTATION(#4282,#4286);
+#4288=PROPERTY_DEFINITION('APP_DATE','user defined attribute',#4177);
+#4292=REPRESENTATION('',(#4291),#4167);
+#4293=PROPERTY_DEFINITION_REPRESENTATION(#4288,#4292);
+#4294=PROPERTY_DEFINITION('DESG','user defined attribute',#4177);
+#4298=REPRESENTATION('',(#4297),#4167);
+#4299=PROPERTY_DEFINITION_REPRESENTATION(#4294,#4298);
+#4300=PROPERTY_DEFINITION('TI_PACKAGE_NAME','user defined attribute',#4177);
+#4304=REPRESENTATION('',(#4303),#4167);
+#4305=PROPERTY_DEFINITION_REPRESENTATION(#4300,#4304);
+#4306=PROPERTY_DEFINITION('INDUSTRY_NAME','user defined attribute',#4177);
+#4310=REPRESENTATION('',(#4309),#4167);
+#4311=PROPERTY_DEFINITION_REPRESENTATION(#4306,#4310);
+#4312=PROPERTY_DEFINITION('LD_CNT','user defined attribute',#4177);
+#4316=REPRESENTATION('',(#4315),#4167);
+#4317=PROPERTY_DEFINITION_REPRESENTATION(#4312,#4316);
+#4319=REPRESENTATION('',(#4318),#4167);
+#4320=PROPERTY_DEFINITION('attribute type designation','Real Number',#4313);
+#4321=PROPERTY_DEFINITION_REPRESENTATION(#4320,#4319);
+#4322=PROPERTY_DEFINITION('LDNO2','user defined attribute',#4177);
+#4326=REPRESENTATION('',(#4325),#4167);
+#4327=PROPERTY_DEFINITION_REPRESENTATION(#4322,#4326);
+#4329=REPRESENTATION('',(#4328),#4167);
+#4330=PROPERTY_DEFINITION('attribute type designation','Real Number',#4323);
+#4331=PROPERTY_DEFINITION_REPRESENTATION(#4330,#4329);
+#4332=PROPERTY_DEFINITION('LDNO3','user defined attribute',#4177);
+#4336=REPRESENTATION('',(#4335),#4167);
+#4337=PROPERTY_DEFINITION_REPRESENTATION(#4332,#4336);
+#4339=REPRESENTATION('',(#4338),#4167);
+#4340=PROPERTY_DEFINITION('attribute type designation','Real Number',#4333);
+#4341=PROPERTY_DEFINITION_REPRESENTATION(#4340,#4339);
+#4342=PROPERTY_DEFINITION('LDNO4','user defined attribute',#4177);
+#4346=REPRESENTATION('',(#4345),#4167);
+#4347=PROPERTY_DEFINITION_REPRESENTATION(#4342,#4346);
+#4349=REPRESENTATION('',(#4348),#4167);
+#4350=PROPERTY_DEFINITION('attribute type designation','Real Number',#4343);
+#4351=PROPERTY_DEFINITION_REPRESENTATION(#4350,#4349);
+#4352=PROPERTY_DEFINITION('LDNO5','user defined attribute',#4177);
+#4356=REPRESENTATION('',(#4355),#4167);
+#4357=PROPERTY_DEFINITION_REPRESENTATION(#4352,#4356);
+#4359=REPRESENTATION('',(#4358),#4167);
+#4360=PROPERTY_DEFINITION('attribute type designation','Real Number',#4353);
+#4361=PROPERTY_DEFINITION_REPRESENTATION(#4360,#4359);
+#4362=PROPERTY_DEFINITION('LDNO6','user defined attribute',#4177);
+#4366=REPRESENTATION('',(#4365),#4167);
+#4367=PROPERTY_DEFINITION_REPRESENTATION(#4362,#4366);
+#4369=REPRESENTATION('',(#4368),#4167);
+#4370=PROPERTY_DEFINITION('attribute type designation','Real Number',#4363);
+#4371=PROPERTY_DEFINITION_REPRESENTATION(#4370,#4369);
+#4372=PROPERTY_DEFINITION('LDNO7','user defined attribute',#4177);
+#4376=REPRESENTATION('',(#4375),#4167);
+#4377=PROPERTY_DEFINITION_REPRESENTATION(#4372,#4376);
+#4379=REPRESENTATION('',(#4378),#4167);
+#4380=PROPERTY_DEFINITION('attribute type designation','Real Number',#4373);
+#4381=PROPERTY_DEFINITION_REPRESENTATION(#4380,#4379);
+#4382=PROPERTY_DEFINITION('LDPITCH_CNT','user defined attribute',#4177);
+#4386=REPRESENTATION('',(#4385),#4167);
+#4387=PROPERTY_DEFINITION_REPRESENTATION(#4382,#4386);
+#4389=REPRESENTATION('',(#4388),#4167);
+#4390=PROPERTY_DEFINITION('attribute type designation','Real Number',#4383);
+#4391=PROPERTY_DEFINITION_REPRESENTATION(#4390,#4389);
+#4392=PROPERTY_DEFINITION('AMAX','user defined attribute',#4177);
+#4396=REPRESENTATION('',(#4395),#4167);
+#4397=PROPERTY_DEFINITION_REPRESENTATION(#4392,#4396);
+#4399=REPRESENTATION('',(#4398),#4167);
+#4400=PROPERTY_DEFINITION('attribute type designation','Real Number',#4393);
+#4401=PROPERTY_DEFINITION_REPRESENTATION(#4400,#4399);
+#4402=PROPERTY_DEFINITION('PKG_NAME','user defined attribute',#4177);
+#4406=REPRESENTATION('',(#4405),#4167);
+#4407=PROPERTY_DEFINITION_REPRESENTATION(#4402,#4406);
+#4408=PROPERTY_DEFINITION('MM_YYYY','user defined attribute',#4177);
+#4412=REPRESENTATION('',(#4411),#4167);
+#4413=PROPERTY_DEFINITION_REPRESENTATION(#4408,#4412);
+ENDSEC;
+END-ISO-10303-21;
examples/jst_connector_generator.pyadded+130
@@ -0,0 +1,130 @@+"""Parametric JST connector generator — runs via fusion_run_modeling_script.++Builds a JST-family through-hole, top-entry header from a family table + pin count:+housing, shrouded mating cavity, the friction-lock window (polarization), and N+square pins. Dimensions are created as editable Fusion user parameters; the solid+is generated from those values (re-run to regenerate at new settings).++Configure by setting CONNECTOR before running (the bridge verb can prepend it):+    CONNECTOR = {"family": "XH", "pins": 4}+Supported families (pitch mm): SH 1.0 · GH 1.25 · ZH 1.5 · PH 2.0 · XH 2.5++Globals provided by the verb: adsk, app, ui, design.+"""++import adsk.core+import adsk.fusion++MM = 0.1  # Fusion internal length unit is cm++# family -> nominal dims (mm)+FAMILIES = {+    "SH": dict(pitch=1.00, bodyW=2.90, bodyH=4.25, wall=0.40, floor=0.50, end=0.90, pin=0.30, pinLen=3.0),+    "GH": dict(pitch=1.25, bodyW=3.00, bodyH=4.25, wall=0.45, floor=0.50, end=0.95, pin=0.30, pinLen=3.0),+    "ZH": dict(pitch=1.50, bodyW=3.50, bodyH=4.50, wall=0.50, floor=0.60, end=1.00, pin=0.40, pinLen=3.2),+    "PH": dict(pitch=2.00, bodyW=4.50, bodyH=4.50, wall=0.60, floor=0.60, end=1.35, pin=0.50, pinLen=3.4),+    "XH": dict(pitch=2.50, bodyW=5.75, bodyH=5.75, wall=0.70, floor=0.70, end=1.45, pin=0.64, pinLen=3.4),+}++cfg = dict(globals().get("CONNECTOR", {}))+fam = str(cfg.get("family", "PH")).upper()+if fam not in FAMILIES:+    raise ValueError(f"Unknown JST family '{fam}'. Choose from {list(FAMILIES)}.")+pins = max(1, int(cfg.get("pins", 2)))+d = FAMILIES[fam]+length_mm = (pins - 1) * d["pitch"] + 2 * d["end"]+part_name = f"JST-{fam} {pins}-pin"++root = design.rootComponent+extrudes = root.features.extrudeFeatures+planes = root.constructionPlanes++# --- editable user parameters (parametric in the Fusion UI) ---+up = design.userParameters+def _param(name, mm_val, comment):+    ex = up.itemByName(name)+    if ex:+        ex.expression = f"{mm_val} mm"+    else:+        up.add(name, adsk.core.ValueInput.createByString(f"{mm_val} mm"), "mm", comment)+for nm, val, cm in [("jst_pitch", d["pitch"], "Pin pitch"), ("jst_pin", d["pin"], "Pin square size"),+                    ("jst_pinLen", d["pinLen"], "Pin length below housing"), ("jst_bodyH", d["bodyH"], "Housing height"),+                    ("jst_bodyW", d["bodyW"], "Housing width"), ("jst_wall", d["wall"], "Shroud wall"),+                    ("jst_length", length_mm, "Housing length (derived)")]:+    _param(nm, val, cm)++L, W, H = length_mm * MM, d["bodyW"] * MM, d["bodyH"] * MM+wall, floor = d["wall"] * MM, d["floor"] * MM++def _rect(sketch, cx, cy, w, h):+    p0 = adsk.core.Point3D.create(cx - w / 2, cy - h / 2, 0)+    p1 = adsk.core.Point3D.create(cx + w / 2, cy + h / 2, 0)+    sketch.sketchCurves.sketchLines.addTwoPointRectangle(p0, p1)+    return sketch.profiles.item(0)++# 1) Housing solid.+sk_body = root.sketches.add(root.xYConstructionPlane)+housing = extrudes.addSimple(_rect(sk_body, 0, 0, L, W), adsk.core.ValueInput.createByReal(H),+                             adsk.fusion.FeatureOperations.NewBodyFeatureOperation)+housing_body = housing.bodies.item(0)+housing_body.name = "housing"++# 2) Shrouded mating cavity (inset, cut down from the top, leaving a floor).+plane_in = planes.createInput()+plane_in.setByOffset(root.xYConstructionPlane, adsk.core.ValueInput.createByReal(H))+top_plane = planes.add(plane_in)+sk_pocket = root.sketches.add(top_plane)+cut_in = extrudes.createInput(_rect(sk_pocket, 0, 0, L - 2 * wall, W - 2 * wall),+                              adsk.fusion.FeatureOperations.CutFeatureOperation)+cut_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(-(H - floor)))+cut_in.participantBodies = [housing_body]+extrudes.add(cut_in)++# 3) Friction-lock window through the front wall (polarization / mating feature).+made_window = False+try:+    front_in = planes.createInput()+    front_in.setByOffset(root.xZConstructionPlane, adsk.core.ValueInput.createByReal(-W / 2))+    front_plane = planes.add(front_in)+    sk_win = root.sketches.add(front_plane)+    win_w, win_h = L * 0.55, H * 0.42+    # sketch plane X->model X, sketch Y->model Z; raise the window toward the top.+    win = extrudes.createInput(_rect(sk_win, 0, H * 0.55, win_w, win_h),+                               adsk.fusion.FeatureOperations.CutFeatureOperation)+    win.setDistanceExtent(False, adsk.core.ValueInput.createByReal(wall * 1.2))+    win.participantBodies = [housing_body]+    extrudes.add(win)+    made_window = True+except Exception as _e:+    print("note: lock window skipped:", _e)++# 4) Pins: one square post extruded down, then rectangular-patterned across the row.+first_x = -((pins - 1) * d["pitch"] * MM) / 2.0+sk_pin = root.sketches.add(root.xYConstructionPlane)+pin_in = extrudes.createInput(_rect(sk_pin, first_x, 0, d["pin"] * MM, d["pin"] * MM),+                              adsk.fusion.FeatureOperations.NewBodyFeatureOperation)+pin_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(-(d["pinLen"] * MM)))+pin_feat = extrudes.add(pin_in)+pin_feat.bodies.item(0).name = "pin"+if pins > 1:+    patterns = root.features.rectangularPatternFeatures+    ents = adsk.core.ObjectCollection.create()+    ents.add(pin_feat)+    pat_in = patterns.createInput(ents, root.xConstructionAxis,+                                  adsk.core.ValueInput.createByReal(pins),+                                  adsk.core.ValueInput.createByReal((pins - 1) * d["pitch"] * MM),+                                  adsk.fusion.PatternDistanceType.ExtentPatternDistanceType)+    pat_in.quantityTwo = adsk.core.ValueInput.createByReal(1)+    pat_in.distanceTwo = adsk.core.ValueInput.createByReal(0)+    patterns.add(pat_in)++try:+    app.activeViewport.fit()+except Exception:+    pass++result = {"part": part_name, "family": fam, "pins": pins, "pitch_mm": d["pitch"],+          "length_mm": round(length_mm, 3), "bodies": root.bRepBodies.count, "lockWindow": made_window}+print(f"Built {part_name}: {pins}p @ {d['pitch']}mm, housing "+      f"{length_mm:.2f}x{d['bodyW']}x{d['bodyH']}mm, {root.bRepBodies.count} bodies"+      f"{' + lock window' if made_window else ''}.")
examples/jst_ph_connector.pyadded+115
@@ -0,0 +1,115 @@+"""Parametric JST-PH (2.0 mm) connector — runs via fusion_run_modeling_script.++Demonstrates the in-app modeling verb: builds a recognizable, parametric JST-PH+style top-entry connector (housing + shrouded mating cavity + N square pins) from+code, in the live Fusion session. FREE (no APS Fusion Automation billing).++Pin count: set `JST_PINS` in the exec namespace before running (the bridge verb+can prepend e.g. `JST_PINS = 4`). Defaults to 2. All dimensions are real JST-PH+nominal values, created as editable Fusion user parameters; the solid is then+generated from those parameter values (re-run to regenerate at new values).++Globals provided by the verb: adsk, app, ui, design.+"""++import adsk.core+import adsk.fusion++MM = 0.1  # Fusion internal length unit is cm; 1 mm = 0.1 cm++# --- parameters (JST-PH 2.0 mm nominal), in mm ---+pins = int(globals().get("JST_PINS", 2))+pitch_mm = 2.0+pin_mm = 0.5     # square pin cross-section+pin_len_mm = 3.4  # pin length below the housing+body_h_mm = 4.5   # housing height+body_w_mm = 4.5   # housing width (across the short axis)+wall_mm = 0.6     # shroud wall thickness+floor_mm = 0.6    # cavity floor thickness+end_mm = 1.35     # housing margin past the outer pins+length_mm = (pins - 1) * pitch_mm + 2 * end_mm++root = design.rootComponent+part_name = f"JST-PH {pins}-pin"  # root component can't be renamed; used for labels++# --- editable user parameters (so the model is parametric in the UI) ---+up = design.userParameters+def _param(name, mm_val, comment):+    existing = up.itemByName(name)+    vi = adsk.core.ValueInput.createByString(f"{mm_val} mm")+    if existing:+        existing.expression = f"{mm_val} mm"+        return existing+    return up.add(name, vi, "mm", comment)++_param("jst_pitch", pitch_mm, "Pin pitch")+_param("jst_pin", pin_mm, "Pin square size")+_param("jst_pinLen", pin_len_mm, "Pin length below housing")+_param("jst_bodyH", body_h_mm, "Housing height")+_param("jst_bodyW", body_w_mm, "Housing width")+_param("jst_wall", wall_mm, "Shroud wall thickness")+_param("jst_length", length_mm, "Housing length (derived)")++L = length_mm * MM+W = body_w_mm * MM+H = body_h_mm * MM+sk_planes = root.constructionPlanes+extrudes = root.features.extrudeFeatures++def _rect(sketch, cx, cy, w, h):+    p0 = adsk.core.Point3D.create(cx - w / 2, cy - h / 2, 0)+    p1 = adsk.core.Point3D.create(cx + w / 2, cy + h / 2, 0)+    sketch.sketchCurves.sketchLines.addTwoPointRectangle(p0, p1)+    return sketch.profiles.item(0)++# 1) Housing solid: centered box, extruded up by H.+sk_body = root.sketches.add(root.xYConstructionPlane)+prof_body = _rect(sk_body, 0, 0, L, W)+housing = extrudes.addSimple(prof_body, adsk.core.ValueInput.createByReal(H),+                             adsk.fusion.FeatureOperations.NewBodyFeatureOperation)+housing_body = housing.bodies.item(0)+housing_body.name = "housing"++# 2) Shroud cavity: inset rectangle on the top face, cut downward leaving a floor.+plane_in = sk_planes.createInput()+plane_in.setByOffset(root.xYConstructionPlane, adsk.core.ValueInput.createByReal(H))+top_plane = sk_planes.add(plane_in)+sk_pocket = root.sketches.add(top_plane)+prof_pocket = _rect(sk_pocket, 0, 0, L - 2 * wall_mm * MM, W - 2 * wall_mm * MM)+cut_in = extrudes.createInput(prof_pocket, adsk.fusion.FeatureOperations.CutFeatureOperation)+cut_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(-(H - floor_mm * MM)))+cut_in.participantBodies = [housing_body]+extrudes.add(cut_in)++# 3) One pin: square post at the first pin location, extruded DOWN by pin_len.+first_x = -((pins - 1) * pitch_mm * MM) / 2.0+sk_pin = root.sketches.add(root.xYConstructionPlane)+prof_pin = _rect(sk_pin, first_x, 0, pin_mm * MM, pin_mm * MM)+pin_in = extrudes.createInput(prof_pin, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)+pin_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(-(pin_len_mm * MM)))+pin_feat = extrudes.add(pin_in)+pin_feat.bodies.item(0).name = "pin"++# 4) Rectangular-pattern the pin N times along X at the pitch.+if pins > 1:+    patterns = root.features.rectangularPatternFeatures+    ents = adsk.core.ObjectCollection.create()+    ents.add(pin_feat)+    qty = adsk.core.ValueInput.createByReal(pins)+    total = adsk.core.ValueInput.createByReal((pins - 1) * pitch_mm * MM)+    pat_in = patterns.createInput(ents, root.xConstructionAxis, qty, total,+                                  adsk.fusion.PatternDistanceType.ExtentPatternDistanceType)+    pat_in.quantityTwo = adsk.core.ValueInput.createByReal(1)+    pat_in.distanceTwo = adsk.core.ValueInput.createByReal(0)+    patterns.add(pat_in)++# Fit the camera so a screenshot shows the part.+try:+    app.activeViewport.fit()+except Exception:+    pass++result = {"part": part_name, "pins": pins, "pitch_mm": pitch_mm,+          "length_mm": round(length_mm, 3), "bodies": root.bRepBodies.count}+print(f"Built {part_name}: {pins} pins @ {pitch_mm}mm pitch, "+      f"housing {length_mm:.2f}x{body_w_mm}x{body_h_mm}mm, {root.bRepBodies.count} bodies.")
fusion_detect.pyadded+254
@@ -0,0 +1,938 @@+"""Auto-detect Fusion 360 installation on Windows."""++import ctypes+import ctypes.wintypes+import json+import os+import re+import subprocess+import sys+import threading+import time+import urllib.error+import urllib.request+from pathlib import Path++ADDIN_PORT = 8774++# Fusion 360 uses a web-deploy model — the launcher lives under+#   <base>\Autodesk\webdeploy\production\<hash>\FusionLauncher.exe+# where <base> is %LOCALAPPDATA% for a per-user install OR %ProgramFiles%+# (/%ProgramFiles(x86)%/%ProgramW6432%) for a SYSTEM-WIDE `--globalinstall` -+# which is exactly what the fusion-onboarding skill runs. We MUST check both, or+# an AI-installed (globalinstall) Fusion is invisible and onboarding "succeeds"+# yet the bridge still reports not-installed. (Found on the ADOMBASELINE test.)+_WEBDEPLOY_BASES = []+for _var in ("LOCALAPPDATA", "ProgramFiles", "ProgramFiles(x86)", "ProgramW6432"):+    _root = os.environ.get(_var)+    if _root:+        _base = Path(_root) / "Autodesk" / "webdeploy" / "production"+        if _base not in _WEBDEPLOY_BASES:+            _WEBDEPLOY_BASES.append(_base)+# Back-compat alias (some callers import WEBDEPLOY_BASE directly).+WEBDEPLOY_BASE = _WEBDEPLOY_BASES[0] if _WEBDEPLOY_BASES else (+    Path(os.environ.get("LOCALAPPDATA", "")) / "Autodesk" / "webdeploy" / "production"+)++# macOS uses the same webdeploy model under ~/Library; the env-var loop above+# finds nothing there (no LOCALAPPDATA), so seed the mac paths explicitly.+IS_MACOS = sys.platform == "darwin"+if IS_MACOS:+    _mac_base = Path.home() / "Library" / "Application Support" / "Autodesk" / "webdeploy" / "production"+    if _mac_base not in _WEBDEPLOY_BASES:+        _WEBDEPLOY_BASES.insert(0, _mac_base)+    WEBDEPLOY_BASE = _WEBDEPLOY_BASES[0]++# EVERY known per-user add-in dir, newest convention first. Fusion MOVED this+# across versions and silently ignores the others (issue #63: an add-in in the+# legacy API\AddIns dir never loads on 2025+ Fusion, which scans FusionAddins -+# proven live on a fresh install). Track ALL of them; never assume one path.+ADDINS_DIR_CANDIDATES = [+    Path(os.environ.get("APPDATA", "")) / "Autodesk" / "FusionAddins",+    Path(os.environ.get("APPDATA", "")) / "Autodesk" / "Autodesk Fusion" / "API" / "AddIns",+    Path(os.environ.get("APPDATA", "")) / "Autodesk" / "Autodesk Fusion 360" / "API" / "AddIns",+] if sys.platform != "darwin" else [+    Path.home() / "Library" / "Application Support" / "Autodesk" / "FusionAddins",+    Path.home() / "Library" / "Application Support" / "Autodesk" / "Autodesk Fusion" / "API" / "AddIns",+    Path.home() / "Library" / "Application Support" / "Autodesk" / "Autodesk Fusion 360" / "API" / "AddIns",+]++# Keep callback references alive to prevent GC+_callbacks = []++# Guard windll so this module imports on non-Windows hosts (galliaApril smoke+# tests, macOS). The Win32-only functions below are never reached off-Windows —+# detect_fusion() short-circuits to installed:False — but the bridge must still+# boot + serve /status on any platform AD spawns it on.+user32 = ctypes.windll.user32 if hasattr(ctypes, "windll") else None+++def detect_fusion() -> dict:+    """Detect Fusion 360 installation. Returns a dict with paths and status."""+    exe_path = _find_fusion_launcher()+    addins_dir = _find_addins_dir()+    addin_installed = _check_addin_installed(addins_dir) if addins_dir else False+    running = _is_fusion_running()++    if exe_path:+        return {+            "installed": True,+            "exe_path": str(exe_path),+            "addins_dir": str(addins_dir) if addins_dir else None,+            "addin_installed": addin_installed,+            "running": running,+        }++    return {+        "installed": False,+        "exe_path": None,+        "addins_dir": str(addins_dir) if addins_dir else None,+        "addin_installed": addin_installed,+        "running": running,+        "error": "Fusion 360 not found",+    }+++# ---------------------------------------------------------------------------------------------------+# INSTALL-COMPLETENESS DETECTION  (root-caused live on a fresh Hyper-V VM, John 2026-07-14)+#+# WHAT A WEBDEPLOY INSTALL ACTUALLY LOOKS LIKE (verified on disk, do not assume):+#   %LOCALAPPDATA%\Autodesk\webdeploy\production\ holds one hash dir PER content-build. A COMPLETE+#   Fusion install is ~615 files (Fusion360.exe ~880 KB + hundreds of DLLs + Qt/ + Python/ + ...).+#   BUT Autodesk ALSO drops a tiny 8-file launcher STUB dir next to it: icons + FusionLauncher.exe+#   + a small FusionLauncher.exe.ini (~412 bytes). So at steady state there are TWO hash dirs.+#+# THE TRAP that broke the fresh VM (and the two earlier "fixes" that were WRONG):+#   * Keying "installed" off FusionLauncher.exe EXISTING -> true mid-stream (launcher lands early) ->+#     premature fusion_start -> "Error Launching Streamed Application ... .ini missing/incomplete".+#   * Keying off FusionLauncher.exe.ini existing / its SIZE -> ALSO wrong: the COMPLETE app dir has+#     NO .ini at all; only the throwaway stub carries a 412-byte .ini. A size gate would REJECT a+#     perfectly good install and ACCEPT nothing. (Measured it: complete app dir = 615 files, no .ini.)+#+# THE RELIABLE SIGNAL: the real application binary Fusion360.exe. It only exists (full size) when the+#   payload finished streaming. Gate "installed" on Fusion360.exe, NEVER on the launcher or its .ini.+# ---------------------------------------------------------------------------------------------------+_FUSION_APP_EXE = "Fusion360.exe"     # the ACTUAL app binary (~880 KB); the completeness marker+_MIN_APP_EXE_BYTES = 200_000          # guards against a 0-byte placeholder the streamer writes early+++def _app_dir_complete(subdir: Path) -> bool:+    """A production hash dir is a COMPLETE Fusion install ONLY when it contains the real app binary+    Fusion360.exe at full size. This is process-independent and version-stable. Do NOT substitute+    FusionLauncher.exe (lands early, mid-stream) or FusionLauncher.exe.ini (absent from the complete+    app dir; only the launcher stub has one). See the block comment above for the on-disk anatomy."""+    exe = subdir / _FUSION_APP_EXE+    try:+        return exe.exists() and exe.stat().st_size >= _MIN_APP_EXE_BYTES+    except OSError:+        return False+++def _any_app_complete() -> bool:+    """True if ANY webdeploy hash dir holds a complete Fusion (Fusion360.exe). This is the single+    source of truth for 'Fusion is installed'."""+    for base in _WEBDEPLOY_BASES:+        try:+            if base.exists():+                for subdir in base.iterdir():+                    if subdir.is_dir() and _app_dir_complete(subdir):+                        return True+        except OSError:+            continue+    return False+++def _find_fusion_launcher() -> Path | None:+    """Return the FusionLauncher.exe to RUN, but only when Fusion is actually INSTALLED.++    TWO SEPARATE QUESTIONS (conflating them is what broke the launch, John 2026-07-14):+      1. Is Fusion installed?  ->  a hash dir contains the real app binary Fusion360.exe.+      2. Which launcher do I run?  ->  a FusionLauncher.exe that HAS its FusionLauncher.exe.ini+         BESIDE IT. Running a FusionLauncher.exe WITHOUT its .ini throws Fusion's own+         "Error Launching Streamed Application ... FusionLauncher.exe.ini is missing or incomplete".+         The complete APP dir (615 files, Fusion360.exe) frequently has the launcher but NO .ini; a+         separate tiny STUB dir carries FusionLauncher.exe + its ~412-byte .ini and knows how to load+         the app. So we must return the launcher-WITH-.ini, NOT the app dir's bare launcher.++    Because we gate on Fusion360.exe first, the stub's .ini is guaranteed complete by then (mid-stream+    there is no Fusion360.exe, so we return None and nothing launches into a half-written install)."""+    if IS_MACOS:+        # The .app bundle sits inside the hash dir (sometimes directly under+        # production/). `open` launches the bundle path; no .ini stub dance.+        for base in _WEBDEPLOY_BASES:+            if not base.exists():+                continue+            try:+                subdirs = sorted(+                    [d for d in base.iterdir() if d.is_dir()],+                    key=lambda d: d.stat().st_mtime,+                    reverse=True,+                )+            except OSError:+                continue+            for subdir in subdirs:+                if subdir.name.endswith(".app") and (subdir / "Contents").exists():+                    return subdir+                app = subdir / "Autodesk Fusion.app"+                if (app / "Contents").exists():+                    return app+        return None++    if not _any_app_complete():+        return None                                   # not installed (or still streaming) -> None++    runnable = []      # (mtime, launcher) - FusionLauncher.exe that has its .ini beside it+    bare = []          # (mtime, launcher) - FusionLauncher.exe with NO .ini (fallback only)+    app_exes = []      # (mtime, Fusion360.exe) - last-ditch fallback+    for base in _WEBDEPLOY_BASES:+        if not base.exists():+            continue+        try:+            subdirs = [d for d in base.iterdir() if d.is_dir()]+        except OSError:+            continue+        for subdir in subdirs:+            try:+                mtime = subdir.stat().st_mtime+            except OSError:+                mtime = 0.0+            launcher = subdir / "FusionLauncher.exe"+            if launcher.exists():+                if (subdir / "FusionLauncher.exe.ini").exists():+                    runnable.append((mtime, launcher))+                else:+                    bare.append((mtime, launcher))+            if _app_dir_complete(subdir):+                app_exes.append((mtime, subdir / _FUSION_APP_EXE))++    for pool in (runnable, bare, app_exes):            # prefer launcher+ini, then bare launcher, then app exe+        if pool:+            pool.sort(key=lambda c: c[0], reverse=True)+            return pool[0][1]+    return None+++def _incomplete_webdeploy_present() -> bool:+    """Disk-state (process-INDEPENDENT) 'a fresh install is actively streaming' signal: some hash dir+    has FusionLauncher.exe but NO complete Fusion360.exe exists ANYWHERE yet. Why disk-state and not a+    tasklist check: the Autodesk streamer spawns short-lived per-chunk worker processes, so+    _installer_running() reads False most of a live multi-GB stream (flickered True only 3 of 25 polls+    during a real install, John 2026-07-14). Why gate on 'no complete app anywhere': once the app IS+    complete, the leftover launcher stub (FusionLauncher.exe, no Fusion360.exe) is NORMAL and must NOT+    read as 'still installing'. (An auto-UPDATE that streams a new build beside a complete old one is+    handled separately by fusion_update_in_progress(), not here.) Never raises."""+    if _any_app_complete():+        return False                                  # a complete install exists -> not installing+    for base in _WEBDEPLOY_BASES:+        try:+            if not base.exists():+                continue+            for subdir in base.iterdir():+                if subdir.is_dir() and (subdir / "FusionLauncher.exe").exists():+                    return True                       # launcher present, no complete app -> streaming+        except OSError:+            continue+    return False+++def _clean_incomplete_webdeploy() -> list:+    """Remove the residue of an INTERRUPTED stream so the next fusion_install_fusion re-streams clean.+    Only ever called AFTER a launch failure (we already know something is corrupt).++    SAFETY GUARD: if a COMPLETE install (Fusion360.exe) exists anywhere, do NOTHING and return [] -+    the launcher-only stub dir beside a complete app is a LEGIT part of the install, not corruption,+    and nuking it would break a working Fusion. Only when NO complete app exists (a genuinely half-+    streamed state) do we remove the partial launcher-bearing dirs. Never raises. (John 2026-07-14:+    the old .ini-size test would have deleted the legit stub of a healthy install.)"""+    import shutil+    if _any_app_complete():+        return []                                     # healthy install present - never touch it+    removed = []+    for base in _WEBDEPLOY_BASES:+        if not base.exists():+            continue+        try: