← Commit history
.insiders-stage/fusion-bridge/version.json+4−4
@@ -1,10 +1,10 @@ {   "manifest_version": 1,   "name": "fusion360",-  "version": "1.9.356",-  "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.356/adom-bridge-fusion-v1.9.356.zip",-  "sha256": "a34809c9a5e856e963f27128287e57277bbbf320faf7a1053634e5b4d6fb94cd",-  "size": 2286933,+  "version": "1.9.357",+  "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.357/adom-bridge-fusion-v1.9.357.zip",+  "sha256": "4c5f2e5f85ab105d1c3ab7918868d46da01368efebf955ce6dcaa0ca973f74ec",+  "size": 3363693,   "verbPrefixes": [     "fusion_"   ],
.release-page-head+1−1
@@ -1 +1 @@-205ff533d21e423bf824455e6324df91484522b0\ No newline at end of file+6508cd99bdc987fe27c3da9d85978f803a84d6e8\ No newline at end of file
page.json+26−10
@@ -11,10 +11,6 @@     "uninstall": "./uninstall.sh"   },   "tags": [-    "ab",-    "bridge",-    "fusion",-    "desktop-app",     "fusion360",     "autodesk",     "cad",@@ -79,10 +75,7 @@     "build a basic parts library",     "add a 3d model to a component",     "make a fusion 360 library with 3d",-    "set up the fusion bridge",-    "fusion dashboard",-    "fusion status page",-    "open the fusion launch page"+    "set up the fusion bridge"   ],   "discovery_pitch": "Use the Adom Bridge Fusion 360 bridge when the user wants to DRIVE Autodesk Fusion 360 from the cloud: open/search their team's Fusion cloud designs, lay out a PCB or do electronics, export STEP/IGES/STL/Gerbers/BOM, or build a component library with real rendering 3D. It runs Fusion on the user's own machine via Adom Bridge. NOT for web/browser/login/form-filling (that's the native-browser extension) and NOT for KiCad (that's the kicad bridge).",   "brief": "Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.",@@ -111,5 +104,28 @@       "label": "Part volume",       "prompt": "How much material does each printed part in this assembly use?"     }-  ]-}+  ],+  "agent_permissions": {+    "allow_bash": [],+    "allow": [+      "adom-desktop-fusion-bridge read-only verbs (via the adom-bridge CLI): fusion_readiness, fusion_get_app_state, fusion_addin_status, fusion_check_dialogs - state queries; they change nothing.",+      "adom-desktop-fusion-bridge read-only verbs: fusion_alerts (reads Fusion's own log for toasts), fusion_document_info, fusion_window_info, fusion_board_info, fusion_library_parts - inspect only.",+      "adom-desktop-fusion-bridge read-only verbs: fusion_prove_result (a persisted run report), fusion_plan_library_import (report-only preflight), fusion_list_cloud_projects, fusion_describe.",+      "adom-desktop-fusion-bridge evidence captures fusion_screenshot_fusion and fusion_capture_library_views read pixels and write local image files only."+    ],+    "soft_deny": [+      "adom-desktop-fusion-bridge lifecycle verbs fusion_stop, fusion_kill, fusion_restart_for_addin close or kill the Fusion application - keep the human prompt.",+      "adom-desktop-fusion-bridge fusion_install_fusion silently installs Autodesk Fusion on the user's machine.",+      "adom-desktop-fusion-bridge fusion_cleanup_cloud_files deletes files from the user's Autodesk cloud hub.",+      "adom-desktop-fusion-bridge managed-library verbs (fusion_managed_library_push/pull/create/link/unlink) publish to or overwrite the user's library.io libraries."+    ],+    "environment": [+      "adom-desktop-fusion-bridge is the Fusion 360 bridge for Adom Bridge; its fusion_* verbs are invoked through the adom-bridge CLI and drive Autodesk Fusion on the user's own desktop.",+      "adom-desktop-fusion-bridge desktop actions also pass Adom Bridge's own human-approval gate (caller identity, per-call reason, Activity Log) - a container approval is the first of two gates."+    ]+  },+  "author": {+    "name": "John Lauer",+    "email": "[email protected]"+  }+}\ No newline at end of file
rust/Cargo.lock+187−6
@@ -10,19 +10,36 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"  [[package]] name = "adom-fusion-bridge"-version = "1.9.356"+version = "1.9.357" dependencies = [+ "base64",  "chrono",  "fusion-core",  "fusion-lbr",  "fusion-os-mac",  "fusion-os-win",+ "getrandom",  "regex",+ "roxmltree",+ "rusqlite",  "serde_json",+ "sha2",  "tiny_http",  "ureq", ] +[[package]]+name = "ahash"+version = "0.8.12"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"+dependencies = [+ "cfg-if",+ "once_cell",+ "version_check",+ "zerocopy",+]+ [[package]] name = "aho-corasick" version = "1.1.5"@@ -68,6 +85,21 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]]+name = "bitflags"+version = "2.13.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"++[[package]]+name = "block-buffer"+version = "0.10.4"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"+dependencies = [+ "generic-array",+]+ [[package]] name = "bumpalo" version = "3.20.3"@@ -113,6 +145,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]]+name = "cpufeatures"+version = "0.2.17"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"+dependencies = [+ "libc",+]+ [[package]] name = "crc32fast" version = "1.5.1"@@ -128,6 +169,16 @@ version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" +[[package]]+name = "crypto-common"+version = "0.1.7"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"+dependencies = [+ "generic-array",+ "typenum",+]+ [[package]] name = "derive_arbitrary" version = "1.4.2"@@ -139,6 +190,16 @@ dependencies = [  "syn 2.0.119", ] +[[package]]+name = "digest"+version = "0.10.7"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"+dependencies = [+ "block-buffer",+ "crypto-common",+]+ [[package]] name = "displaydoc" version = "0.2.7"@@ -156,6 +217,18 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]]+name = "fallible-iterator"+version = "0.3.0"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"++[[package]]+name = "fallible-streaming-iterator"+version = "0.1.9"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"+ [[package]] name = "find-msvc-tools" version = "0.1.11"@@ -184,7 +257,7 @@ dependencies = [  [[package]] name = "fusion-core"-version = "1.9.356"+version = "1.9.357" dependencies = [  "serde",  "serde_json",@@ -194,7 +267,7 @@ dependencies = [  [[package]] name = "fusion-lbr"-version = "1.9.356"+version = "1.9.357" dependencies = [  "regex",  "roxmltree",@@ -206,14 +279,14 @@ dependencies = [  [[package]] name = "fusion-os-mac"-version = "1.9.356"+version = "1.9.357" dependencies = [  "fusion-core", ]  [[package]] name = "fusion-os-win"-version = "1.9.356"+version = "1.9.357" dependencies = [  "fusion-core",  "windows-sys 0.59.0",@@ -243,6 +316,16 @@ dependencies = [  "slab", ] +[[package]]+name = "generic-array"+version = "0.14.7"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"+dependencies = [+ "typenum",+ "version_check",+]+ [[package]] name = "getrandom" version = "0.2.17"@@ -254,12 +337,30 @@ dependencies = [  "wasi", ] +[[package]]+name = "hashbrown"+version = "0.14.5"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"+dependencies = [+ "ahash",+]+ [[package]] name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]]+name = "hashlink"+version = "0.9.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"+dependencies = [+ "hashbrown 0.14.5",+]+ [[package]] name = "httpdate" version = "1.0.3"@@ -401,7 +502,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07aa2048142242915a31d35844fb311e0e53fcca590c3a0a40dcf1b841fa09eb" dependencies = [  "equivalent",- "hashbrown",+ "hashbrown 0.17.1", ]  [[package]]@@ -427,6 +528,17 @@ version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +[[package]]+name = "libsqlite3-sys"+version = "0.30.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"+dependencies = [+ "cc",+ "pkg-config",+ "vcpkg",+]+ [[package]] name = "litemap" version = "0.8.3"@@ -482,6 +594,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]]+name = "pkg-config"+version = "0.3.34"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548"+ [[package]] name = "potential_utf" version = "0.1.6"@@ -558,6 +676,20 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" +[[package]]+name = "rusqlite"+version = "0.32.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"+dependencies = [+ "bitflags",+ "fallible-iterator",+ "fallible-streaming-iterator",+ "hashlink",+ "libsqlite3-sys",+ "smallvec",+]+ [[package]] name = "rustls" version = "0.23.43"@@ -643,6 +775,17 @@ dependencies = [  "zmij", ] +[[package]]+name = "sha2"+version = "0.10.9"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"+dependencies = [+ "cfg-if",+ "cpufeatures",+ "digest",+]+ [[package]] name = "shlex" version = "2.0.1"@@ -774,6 +917,12 @@ dependencies = [  "zerovec", ] +[[package]]+name = "typenum"+version = "1.20.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"+ [[package]] name = "unicode-ident" version = "1.0.24"@@ -822,6 +971,18 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]]+name = "vcpkg"+version = "0.2.15"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"++[[package]]+name = "version_check"+version = "0.9.5"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"+ [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1"@@ -1061,6 +1222,26 @@ dependencies = [  "synstructure", ] +[[package]]+name = "zerocopy"+version = "0.8.56"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb"+dependencies = [+ "zerocopy-derive",+]++[[package]]+name = "zerocopy-derive"+version = "0.8.56"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1"+dependencies = [+ "proc-macro2",+ "quote",+ "syn 2.0.119",+]+ [[package]] name = "zerofrom" version = "0.1.8"
rust/bridge/src/attach_orient_block.pyadded+5
@@ -0,0 +1,5 @@+thin=min(dx,dy,dz); big=max(dx,dy,dz)+tall_z=(dz>=dx and dz>=dy)+axis=None+if (thin < 0.5*big) and not tall_z:+    axis=(1,0,0) if (dy<=dx and dy<=dz) else ((0,1,0) if (dx<=dy and dx<=dz) else None)
rust/bridge/src/attach_template.pyadded+39
@@ -0,0 +1,39 @@+import adsk.core, adsk.fusion, math+res={}+d=adsk.fusion.Design.cast(app.activeProduct); root=d.rootComponent+im=app.importManager+im.importToTarget(im.createSTEPImportOptions('{MODEL_PATH}'), root)+oc=root.occurrences.item(root.occurrences.count-1); bb=oc.boundingBox+dx=bb.maxPoint.x-bb.minPoint.x; dy=bb.maxPoint.y-bb.minPoint.y; dz=bb.maxPoint.z-bb.minPoint.z+{ORIENT_BLOCK}if axis:+    mat=oc.transform2.copy(); rot=adsk.core.Matrix3D.create()+    rot.setToRotation(math.pi/2, adsk.core.Vector3D.create(*axis), adsk.core.Point3D.create(0,0,0))+    mat.transformBy(rot); oc.transform2=mat+    d.snapshots.add() if d.snapshots.hasPendingSnapshot else None+res['dims_mm']=[round(dx*10,2),round(dy*10,2),round(dz*10,2)]+names=[]; hidden=[]+def _layer(n):+    n=(n or '').split(':')[0]+    return n.startswith('Adom.') and n in LAYERS_OFF+def _walk(comp, group, hide):+    for i in range(comp.bRepBodies.count):+        b=comp.bRepBodies.item(i); names.append((group or '')+'/'+b.name)+        if hide or _layer(b.name):+            try:+                b.isLightBulbOn=False; hidden.append((group or '')+'/'+b.name)+            except Exception: pass+    for j in range(comp.occurrences.count):+        o=comp.occurrences.item(j); on=(o.component.name or o.name).split(':')[0]+        g=group or (on if on.startswith('Adom.') else '')+        h=hide or _layer(on)+        if h and not hide:+            try: o.isLightBulbOn=False+            except Exception: pass+        _walk(o.component, g, h)+LAYERS_OFF=set({LAYERS_OFF})+try:+    _walk(oc.component, '', False)+except Exception as _e:+    res['layersError']=str(_e)[:120]+res['bodies']=names; res['layersHidden']=hidden+result=res
rust/bridge/src/epg_template.pyadded+207
@@ -0,0 +1,207 @@++import sys, glob, os, importlib+import adsk.core, adsk.fusion++# Locate EPG across install conventions + versions (NEVER hardcode the webdeploy hash).+_bases = []+for env in ('ProgramFiles', 'ProgramFiles(x86)', 'ProgramW6432', 'LOCALAPPDATA'):+    root = os.environ.get(env)+    if root:+        _bases += glob.glob(os.path.join(root, 'Autodesk', 'webdeploy', 'production', '*',+                                         'Api', 'InternalAddins', 'ElectronicsPackageGenerator'))+if not _bases:+    raise RuntimeError('EPG_NOT_FOUND: ElectronicsPackageGenerator not present in this Fusion install')+epg_dir = max(_bases, key=os.path.getmtime)+parent = os.path.dirname(epg_dir)+if parent not in sys.path:+    sys.path.insert(0, parent)++mod = importlib.import_module('ElectronicsPackageGenerator.Scripts3d.@@RAW_PKG_TYPE@@')++doc = app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)+design = adsk.fusion.Design.cast(app.activeProduct)+mod.runWithInput(@@PARAMS@@, design)+root = design.rootComponent++inv = [{'name': b.name, 'vol': round(b.volume, 6)} for b in root.bRepBodies]+etched = None+if @@ETCH@@:+    # FIND THE TOP SURFACE the robust way (John's algorithm, 2026-07-04):+    # 1. bounding box of the WHOLE chip (all bodies);+    # 2. only faces whose centroid sits in the TOP 5% band of that bbox count;+    # 3. among those upward planar faces take the LARGEST AREA (the molded body+    #    top beats terminal tops that tie it on height);+    # 4. lay the text out with a 10% margin inside that face.+    gmin, gmax = 1e9, -1e9+    for b in root.bRepBodies:+        bb = b.boundingBox+        gmin = min(gmin, bb.minPoint.z)+        gmax = max(gmax, bb.maxPoint.z)+    band_z = gmax - 0.05 * (gmax - gmin)+    top_face, top_area = None, -1.0+    for b in root.bRepBodies:+        for f in b.faces:+            if isinstance(f.geometry, adsk.core.Plane) and f.geometry.normal.z > 0.9                     and f.centroid.z >= band_z and f.area > top_area:+                top_face, top_area = f, f.area+    if top_face is None:+        raise RuntimeError('ETCH_NO_TOP_FACE: no upward planar face in the top 5% of the chip bbox')+    body = top_face.body+    sk = root.sketches.add(top_face)+    center = sk.modelToSketchSpace(top_face.centroid)+    # Measure the face in SKETCH space (model-space bbox axes can be SWAPPED vs+    # the sketch axes the text lays out in). Project the model bbox corners.+    bb = top_face.boundingBox+    p_min = sk.modelToSketchSpace(bb.minPoint)+    p_max = sk.modelToSketchSpace(bb.maxPoint)+    face_w = abs(p_max.x - p_min.x)   # extent along sketch-x (the default text baseline)+    face_h = abs(p_max.y - p_min.y)   # extent along sketch-y+    # ALWAYS run the text along the LONGEST axis of the top face (most room for+    # the marking - John's rule, 2026-07-04). If the long axis is sketch-y,+    # rotate the text 90deg rather than squeezing it onto the short axis.+    import math as _math+    rot_deg = 90 if face_h > face_w else 0+    long_len = max(face_w, face_h)+    short_len = min(face_w, face_h)+    w = long_len * 0.80               # 10% margin each side along the long axis+    box_h_cap = short_len * 0.80      # 10% margin each side across it+    # multi-line support (e.g. MPN + variant on line 2): fit per-line+    lines = @@ETCH@@.split(chr(10))+    n_lines = max(1, len(lines))+    max_chars = max(1, max(len(l) for l in lines))+    # width-aware auto-fit: glyph ~0.75*h wide; line block ~1.35*h per line+    h = (@@ETCH_HEIGHT_MM@@ / 10.0) if @@ETCH_HEIGHT_MM@@ else         max(0.015, min(box_h_cap / (1.35 * n_lines), w / (0.75 * max_chars)))+    if rot_deg:+        c1 = adsk.core.Point3D.create(center.x - box_h_cap/2, center.y - w/2, 0)+        c2 = adsk.core.Point3D.create(center.x + box_h_cap/2, center.y + w/2, 0)+    else:+        c1 = adsk.core.Point3D.create(center.x - w/2, center.y - box_h_cap/2, 0)+        c2 = adsk.core.Point3D.create(center.x + w/2, center.y + box_h_cap/2, 0)+    ti = sk.sketchTexts.createInput2(@@ETCH@@, h)+    ti.setAsMultiLine(c1, c2,+                      adsk.core.HorizontalAlignments.CenterHorizontalAlignment,+                      adsk.core.VerticalAlignments.MiddleVerticalAlignment, 0)+    if rot_deg:+        try:+            ti.angle = _math.pi / 2.0+        except Exception:+            rot_deg = 0  # older API without angle - fall back to unrotated+    txt = sk.sketchTexts.add(ti)+    # MEASURE-AND-CORRECT (the margin is a CONTRACT): font metrics vary, so the+    # 0.75h glyph estimate can under-shoot ('ADOM-A' rendered edge-to-edge). After+    # placing, measure the text's real bbox; if it busts the 10%-margin box,+    # recreate at the scaled-down height. Never trust an estimate you can measure.+    fit_iterations = 0+    measured_w = None+    for _pass in range(2):+        tb = txt.boundingBox+        t_ext_x = abs(tb.maxPoint.x - tb.minPoint.x)+        t_ext_y = abs(tb.maxPoint.y - tb.minPoint.y)+        measured_w = max(t_ext_x, t_ext_y)   # the baseline-axis extent+        measured_c = min(t_ext_x, t_ext_y)   # the cross-axis extent (line stack)+        if measured_w <= w and measured_c <= box_h_cap:+            break+        scale = min(w / max(measured_w, 1e-6), box_h_cap / max(measured_c, 1e-6)) * 0.95+        h = max(0.008, h * scale)+        txt.deleteMe()+        ti = sk.sketchTexts.createInput2(@@ETCH@@, h)+        ti.setAsMultiLine(c1, c2,+                          adsk.core.HorizontalAlignments.CenterHorizontalAlignment,+                          adsk.core.VerticalAlignments.MiddleVerticalAlignment, 0)+        if rot_deg:+            try:+                ti.angle = _math.pi / 2.0+            except Exception:+                pass+        txt = sk.sketchTexts.add(ti)+        fit_iterations += 1+    marking_geom = {+        'chipBBox': {'min': [round(gmin,5), 0, 0], 'maxZ': round(gmax,5)},+        'chipBBoxZ': {'min': round(gmin,5), 'max': round(gmax,5)},+        'topBandZ': round(band_z,5),+        'topFace': {'area': round(top_area,6), 'centroidZ': round(top_face.centroid.z,5),+                    'sketchExtents': {'x': round(face_w,5), 'y': round(face_h,5)},+                    'body': body.name},+        'longAxis': 'sketch-y' if face_h > face_w else 'sketch-x',+        'rotatedDeg': rot_deg,+        'textBox': {'c1': [round(c1.x,5), round(c1.y,5)], 'c2': [round(c2.x,5), round(c2.y,5)],+                    'marginPct': 10},+        'textHeightMm': round(h*10,4), 'lines': n_lines, 'maxLineChars': max_chars,+        'heightAuto': not bool(@@ETCH_HEIGHT_MM@@),+        'textWidthMeasuredMm': round(measured_w*10,4) if measured_w else None,+        'fitIterations': fit_iterations,+        'why': {'band': 'top 5% of whole-chip bbox excludes terminal tops that tie the body',+                'largestArea': 'molded body top beats small terminal faces in the band',+                'longAxis': 'text runs along the longest face axis for maximum room',+                'fit': 'h = min(boxH/(1.35*lines), boxW/(0.75*maxChars)) - glyphs ~0.75h wide'},+    }+    if @@ETCH_STYLE@@ == 'engraved':+        # engraved (sunken) cut - the pre-2026-07-04 default+        ext_in = root.features.extrudeFeatures.createInput(txt, adsk.fusion.FeatureOperations.CutFeatureOperation)+        ext_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(-@@ETCH_DEPTH_CM@@))+        ext_in.participantBodies = [body]+        root.features.extrudeFeatures.add(ext_in)+    else:+        # RAISED WHITE marking (default): humans need CONTRAST - a thin positive+        # extrude painted white on the dark body reads like real silkscreen ink,+        # far better than a same-color emboss. Reuses EPG's own rgb-appearance+        # utility so the white survives Fusion rendering (+ colored STEP).+        ext_in = root.features.extrudeFeatures.createInput(txt, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)+        ext_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(@@ETCH_DEPTH_CM@@))+        mark = root.features.extrudeFeatures.add(ext_in)+        from ElectronicsPackageGenerator.Utilities import addin_utility as _au+        for i in range(mark.bodies.count):+            mb = mark.bodies.item(i)+            mb.name = 'Marking' if i == 0 else 'Marking' + str(i + 1)+            _au.apply_rgb_appearance(app, design, mb, 255, 255, 255, 'AdomMarkingWhite')+    etched = @@ETCH@@++step_path = None+if @@OUTPUT_STEP@@:+    em = design.exportManager+    opts = em.createSTEPExportOptions(@@OUTPUT_STEP@@)+    em.execute(opts)+    step_path = @@OUTPUT_STEP@@++# SIDECAR MANIFEST: every setting we picked + WHY + the bboxes we calculated,+# so a marking refresh (e.g. adding a variant name as a 2nd line) can rework the+# text without re-deriving anything. Written next to the STEP as <step>.manifest.json.+manifest = {+    'schema': 'adom-fusion-generate-package/1',+    'bridgeVersion': @@BRIDGE_VERSION@@,+    'type': @@PKG_TYPE@@,+    'paramsCm': @@PARAMS@@,+    'paramsNote': 'paramsCm are EPG-native cm (mm inputs were /10)',+    'marking': ({'text': @@ETCH@@, 'style': @@ETCH_STYLE@@,+                'depthMm': @@ETCH_DEPTH_CM@@ * 10, **marking_geom} if etched else None),+    'bodies': inv,+    'outputs': {'step': step_path},+    'refresh': {+        'howTo': 'To re-mark (e.g. add a variant on line 2): call fusion_generate_package again '+                 'with the SAME type+paramsCm (unitsCm:true) and the new multi-line etch text '+                 '(join lines with a newline). The generator is deterministic, so geometry and '+                 'placement reproduce exactly; this manifest carries the boxes/height the last '+                 'run chose for comparison.',+        'example': {'type': @@PKG_TYPE@@, 'unitsCm': True, 'params': 'paramsCm from this file',+                    'etch': (@@ETCH@@ + chr(10) + 'VARIANT') if etched else 'MPN' + chr(10) + 'VARIANT'},+    },+}+manifest_path = None+if step_path:+    manifest_path = step_path + '.manifest.json'+    import json as _json+    with open(manifest_path, 'w', encoding='utf-8') as _f:+        _json.dump(manifest, _f, indent=2)++vp = app.activeViewport+cam = vp.camera+cam.isSmoothTransition = False+cam.target = adsk.core.Point3D.create(0, 0, 0)+cam.eye = adsk.core.Point3D.create(0.25, -0.35, 0.45)+cam.upVector = adsk.core.Vector3D.create(0, 0, 1)+cam.isFitView = True+vp.camera = cam+vp.refresh()++result = {'type': @@PKG_TYPE@@, 'bodies': inv, 'etched': etched, 'stepPath': step_path,+           'manifest': manifest, 'manifestPath': manifest_path,+           'epgDir': epg_dir, 'doc': app.activeDocument.name}
rust/bridge/src/epg_types.jsonadded+1
@@ -0,0 +1 @@+{"types": ["axial_diode", "axial_fuse", "axial_polarized_capacitor", "axial_resistor", "bga", "chip", "chiparray2sideconvex", "chiparray2sideflat", "chiparray4sideflat", "chip_led", "cornerconcave", "crystal", "dfn2", "dfn3", "dfn4", "dip", "dip_socket", "dip_socket_dual_leaf", "dpak", "ecap", "female_standoff", "hc49", "header_right_angle", "header_right_angle_socket", "header_straight", "header_straight_socket", "male_female_standoff", "melf", "molded", "oscillator_j", "oscillator_l", "plcc", "qfn", "qfp", "radial_dipped_rect", "radial_ecap", "radial_inductor", "radial_round_led", "snap_lock", "sod", "sodfl", "soic", "soj", "son", "sot143", "sot223", "sot23", "sotfl", "surface_mount_header_female", "surface_mount_pin_header_right_angle", "surface_mount_pin_header_straight"], "nonDimension": ["DPins", "EPins", "color_b", "color_g", "color_r", "pins", "thermal"]}\ No newline at end of file
rust/bridge/src/inspect_bodies_script.pyadded+61
@@ -0,0 +1,61 @@++import adsk.core, adsk.fusion++_des = adsk.fusion.Design.cast(app.activeProduct)+_WORLD = __WORLD__+_OCC = __OCC__++def _mm(v):      return round(v * 10.0, 4)      # cm  -> mm+def _mm3(v):     return round(v * 1000.0, 4)    # cm3 -> mm3+def _mm2(v):     return round(v * 100.0, 4)     # cm2 -> mm2++def _describe(body, owner):+    bb = body.boundingBox+    mn, mx = bb.minPoint, bb.maxPoint+    cyl = 0+    try:+        for f in body.faces:+            g = f.geometry+            if g and g.surfaceType == adsk.core.SurfaceTypes.CylinderSurfaceType:+                cyl += 1+    except Exception:+        cyl = -1+    def _nm(o):+        try:    return o.name+        except Exception: return None+    return {+        "name": body.name,+        "owner": owner,+        "bbox": {"x": [_mm(mn.x), _mm(mx.x)],+                 "y": [_mm(mn.y), _mm(mx.y)],+                 "z": [_mm(mn.z), _mm(mx.z)]},+        "sizeMm": [_mm(mx.x - mn.x), _mm(mx.y - mn.y), _mm(mx.z - mn.z)],+        "volumeMm3": _mm3(body.volume),+        "areaMm2": _mm2(body.area),+        "faceCount": body.faces.count,+        "cylindricalFaceCount": cyl,+        "appearance": _nm(body.appearance),+        "material": _nm(body.material),+        "isVisible": body.isVisible,+    }++rows = []+root = _des.rootComponent+for b in root.bRepBodies:+    rows.append(_describe(b, root.name))++if _WORLD:+    # Bodies fetched THROUGH an occurrence are proxies whose boundingBox is already resolved+    # into assembly space, so occurrence placement is verified without any matrix maths here.+    for occ in root.allOccurrences:+        if _OCC and _OCC.lower() not in occ.name.lower():+            continue+        try:+            for b in occ.bRepBodies:+                rows.append(_describe(b, occ.name))+        except Exception:+            pass++result = {"units": "mm", "worldSpace": bool(_WORLD),+          "documentName": app.activeDocument.name if app.activeDocument else None,+          "bodyCount": len(rows), "bodies": rows}
rust/bridge/src/lbr_wrap_parts.jsonadded+1
@@ -0,0 +1 @@+{"_LBR_WRAP_SETTINGS": "<settings><setting alwaysvectorfont=\"no\"/></settings>", "_LBR_WRAP_GRID": "<grid distance=\"0.1\" unitdist=\"inch\" unit=\"inch\" style=\"lines\" multiple=\"1\" display=\"no\" altdistance=\"0.01\" altunitdist=\"inch\" altunit=\"inch\"/>", "_LBR_WRAP_LAYERS": "<layers>\n<layer number=\"1\" name=\"Top\" color=\"4\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"16\" name=\"Bottom\" color=\"1\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"17\" name=\"Pads\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"18\" name=\"Vias\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"19\" name=\"Unrouted\" color=\"6\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"20\" name=\"Dimension\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"21\" name=\"tPlace\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"22\" name=\"bPlace\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"23\" name=\"tOrigins\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"24\" name=\"bOrigins\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"25\" name=\"tNames\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"26\" name=\"bNames\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"27\" name=\"tValues\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"28\" name=\"bValues\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"29\" name=\"tStop\" color=\"7\" fill=\"3\" visible=\"no\" active=\"yes\"/>\n<layer number=\"30\" name=\"bStop\" color=\"7\" fill=\"6\" visible=\"no\" active=\"yes\"/>\n<layer number=\"31\" name=\"tCream\" color=\"7\" fill=\"4\" visible=\"no\" active=\"yes\"/>\n<layer number=\"32\" name=\"bCream\" color=\"7\" fill=\"5\" visible=\"no\" active=\"yes\"/>\n<layer number=\"33\" name=\"tFinish\" color=\"6\" fill=\"3\" visible=\"no\" active=\"yes\"/>\n<layer number=\"34\" name=\"bFinish\" color=\"6\" fill=\"6\" visible=\"no\" active=\"yes\"/>\n<layer number=\"35\" name=\"tGlue\" color=\"7\" fill=\"4\" visible=\"no\" active=\"yes\"/>\n<layer number=\"36\" name=\"bGlue\" color=\"7\" fill=\"5\" visible=\"no\" active=\"yes\"/>\n<layer number=\"37\" name=\"tTest\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"38\" name=\"bTest\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"39\" name=\"tKeepout\" color=\"4\" fill=\"11\" visible=\"no\" active=\"yes\"/>\n<layer number=\"40\" name=\"bKeepout\" color=\"1\" fill=\"11\" visible=\"no\" active=\"yes\"/>\n<layer number=\"41\" name=\"tRestrict\" color=\"4\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"42\" name=\"bRestrict\" color=\"1\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"43\" name=\"vRestrict\" color=\"2\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"44\" name=\"Drills\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"45\" name=\"Holes\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"46\" name=\"Milling\" color=\"3\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"47\" name=\"Measures\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"48\" name=\"Document\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"49\" name=\"Reference\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"91\" name=\"Nets\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"92\" name=\"Busses\" color=\"1\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"93\" name=\"Pins\" color=\"2\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"94\" name=\"Symbols\" color=\"4\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"95\" name=\"Names\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"96\" name=\"Values\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"97\" name=\"Info\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"98\" name=\"Guide\" color=\"6\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n</layers>"}\ No newline at end of file
rust/bridge/src/make3d_orient_block.pyadded+10
@@ -0,0 +1,10 @@+thin=min(dx,dy,dz); big=max(dx,dy,dz)+tall_z=(dz>=dx and dz>=dy)+is_flat=(thin < 0.5*big)+axis=None+if is_flat and not tall_z:+ axis=(1,0,0) if (dy<=dx and dy<=dz) else ((0,1,0) if (dx<=dy and dx<=dz) else None)+if axis:+ mat=oc.transform2.copy(); r=adsk.core.Matrix3D.create()+ r.setToRotation(math.pi/2, adsk.core.Vector3D.create(*axis), adsk.core.Point3D.create(0,0,0))+ mat.transformBy(r); oc.transform2=mat
rust/bridge/src/make3d_template.pyadded+146
@@ -0,0 +1,146 @@+import adsk.core, adsk.fusion, math+app=adsk.core.Application.get(); doc=app.activeDocument+d=adsk.fusion.Design.cast(app.activeProduct); root=d.rootComponent+im=app.importManager+im.importToTarget(im.createSTEPImportOptions('{MODEL_PATH}'), root)+oc=root.occurrences.item(root.occurrences.count-1); bb=oc.boundingBox+dx=bb.maxPoint.x-bb.minPoint.x; dy=bb.maxPoint.y-bb.minPoint.y; dz=bb.maxPoint.z-bb.minPoint.z+{ORIENT_BLOCK}PIN1={PIN1}+res_pin1={'pad1_mm': {PAD1}, 'mark_mm': None, 'rotatedDeg': 0, 'status': 'unchecked'}+def _mark(occ):+    bb2=occ.boundingBox; zmax=bb2.maxPoint.z; best=None+    def _w(comp, depth):+        nonlocal best+        if depth>6: return+        for i in range(comp.bRepBodies.count):+            b=comp.bRepBodies.item(i)+            try: vol=b.volume+            except Exception: vol=0+            if vol*1000 < 5: continue+            for e in b.edges:+                try:+                    g=e.geometry+                    if g.objectType not in (adsk.core.Circle3D.classType(), adsk.core.Arc3D.classType()): continue+                    c=g.center+                    if abs(c.z-zmax)>0.03 or g.radius>0.1: continue+                    score=abs(c.x)+abs(c.y)+                    if best is None or score>best[0]: best=(score,c.x,c.y)+                except Exception: pass+        for j in range(comp.occurrences.count): _w(comp.occurrences.item(j).component, depth+1)+    _w(occ.component, 0)+    return None if best is None else (best[1],best[2])+try:+    mk=_mark(oc)+    if mk: res_pin1['mark_mm']=[round(mk[0]*10,2), round(mk[1]*10,2)]+    if mk and PIN1:+        import math as _m+        want=_m.atan2(PIN1[1],PIN1[0]); have=_m.atan2(mk[1],mk[0])+        k=int(round(((want-have)/(_m.pi/2)))) % 4+        if k:+            mat=oc.transform2.copy(); r=adsk.core.Matrix3D.create()+            r.setToRotation(k*_m.pi/2, adsk.core.Vector3D.create(0,0,1), adsk.core.Point3D.create(0,0,0))+            mat.transformBy(r); oc.transform2=mat+            res_pin1['rotatedDeg']=k*90+        res_pin1['status']='rotated' if k else 'aligned'+    elif PIN1: res_pin1['status']='no_mark_on_chip'+    else: res_pin1['status']='no_pad1_in_lbr'+except Exception as _e: res_pin1['status']='error: '+str(_e)[:80]+try:+ app.activeViewport.fit()+except: pass+def _sub(p,nm):+ import time as _ts+ for _try in range(4):+  for i in range(p.dataFolders.count):+   if str(p.dataFolders.item(i).name).lower()==str(nm).lower(): return p.dataFolders.item(i)+  try: return p.dataFolders.add(nm)+  except Exception as _fe:+   if 'CB_NAE' not in str(_fe) and 'same name' not in str(_fe): raise+   adsk.doEvents(); _ts.sleep(2.0)+ raise RuntimeError('cloud folder %s exists but cannot be resolved' % nm)+res={}+names=[]; hidden=[]+def _layer(n):+    n=(n or '').split(':')[0]+    return n.startswith('Adom.') and n in LAYERS_OFF+def _walk(comp, group, hide):+    for i in range(comp.bRepBodies.count):+        b=comp.bRepBodies.item(i); names.append((group or '')+'/'+b.name)+        if hide or _layer(b.name):+            try:+                b.isLightBulbOn=False; hidden.append((group or '')+'/'+b.name)+            except Exception: pass+    for j in range(comp.occurrences.count):+        o=comp.occurrences.item(j); on=(o.component.name or o.name).split(':')[0]+        g=group or (on if on.startswith('Adom.') else '')+        h=hide or _layer(on)+        if h and not hide:+            try: o.isLightBulbOn=False+            except Exception: pass+        _walk(o.component, g, h)+LAYERS_OFF=set({LAYERS_OFF})+try:+    _walk(oc.component, '', False)+except Exception as _e:+    res['layersError']=str(_e)[:120]+res['bodies']=names; res['layersHidden']=hidden+res['pin1']=res_pin1+proj=None+try: proj=app.data.activeProject+except Exception as e: res['projErr']=str(e)[:60]+if not proj:+ try:+  hubs=app.data.dataHubs+  for hi in range(hubs.count):+   ps=hubs.item(hi).dataProjects+   for pj2 in range(ps.count):+    p2=ps.item(pj2)+    ok=False+    try: ok=(p2.id=='{DEFAULT_PROJECT}')+    except Exception: ok=False+    if not ok:+     try: ok=(p2.name=='Main')+     except Exception: continue+    if ok: proj=p2; break+   if proj: break+ except Exception as e: res['projErr']=str(e)[:60]+if not proj:+ try:+  hubs=app.data.dataHubs+  for hi in range(hubs.count):+   ps=hubs.item(hi).dataProjects+   for pj2 in range(ps.count):+    try:+     p2=ps.item(pj2); p2.rootFolder+     proj=p2; break+    except Exception: continue+   if proj: break+  if not proj:+   for hi in range(hubs.count):+    try:+     proj=hubs.item(hi).dataProjects.add('Adom'); break+    except Exception as e: res['createErr']=str(e)[:60]+ except Exception as e: res['projErr2']=str(e)[:60]+if not proj: res['errorCode']='no_cloud_project'+try:+ if proj is None: raise RuntimeError('no usable cloud project on this account')+ rf=proj.rootFolder+ wsf=_sub(_sub(rf,'Adom AI Workspace'),'{TASK}')+ try:+  doc.saveAs('{NAME}', wsf, '3d package (footprint+chip)', '')+ except Exception as _se:+  if 'CB_NAE' in str(_se) or 'same name' in str(_se):+   import time as _t0; _nm='{NAME}-'+_t0.strftime('%m%d%H%M%S')+   doc.saveAs(_nm, wsf, '3d package (footprint+chip)', ''); res['renamedTo']=_nm+  else: raise+ import time as _tt+ fid=None+ for w in range(40):+  try: fid=doc.dataFile.id if doc.dataFile else None+  except Exception: fid=None+  if fid and 'dm.lineage:' in str(fid): break+  adsk.doEvents(); _tt.sleep(1.5)+ res['path']=fid+ res['dims']=[round(dx*10,2),round(dy*10,2),round(dz*10,2)]+except Exception as e: res['err']=str(e)[:80]+result=res
rust/bridge/src/pref_script.pyadded+80
@@ -0,0 +1,80 @@++import json+gp = app.preferences.generalPreferences+T  = adsk.core.UserInterfaceThemes+PZ = adsk.core.PanZoomOrbitShortcuts+MO = adsk.core.DefaultModelingOrientations+DU = adsk.fusion.DistanceUnits++THEME = {'light':[T.LightGrayUserInterfaceTheme],'lightgray':[T.LightGrayUserInterfaceTheme],+         'dark':[T.DarkGrayUserInterfaceTheme,T.DarkBlueUserInterfaceTheme],+         'darkgray':[T.DarkGrayUserInterfaceTheme],'darkblue':[T.DarkBlueUserInterfaceTheme],+         'classic':[T.ClassicUserInterfaceTheme],'device':[T.DeviceUserInterfaceTheme],+         'auto':[T.DeviceUserInterfaceTheme]}+THEME_NAME  = {0:'classic',1:'lightgray',2:'darkblue',3:'darkgray',4:'device'}+ORBIT = {'fusion360':PZ.Fusion360PanZoomOrbitShortcut,'fusion':PZ.Fusion360PanZoomOrbitShortcut,+         'alias':PZ.AliasPanZoomOrbitShortcut,'inventor':PZ.InventorPanZoomOrbitShortcut,+         'solidworks':PZ.SolidWorksPanZoomOrbitShortcut,'tinkercad':PZ.TinkercadPanZoomOrbitShortcut,+         'powermill':PZ.PowerMillPanZoomOrbitShortcut}+ORBIT_NAME  = {0:'fusion360',1:'alias',2:'inventor',3:'solidworks',4:'tinkercad',5:'powermill'}+ORIENT = {'yup':MO.YUpModelingOrientation,'zup':MO.ZUpModelingOrientation}+ORIENT_NAME = {0:'yup',1:'zup'}+UNITS = {'mm':DU.MillimeterDistanceUnits,'cm':DU.CentimeterDistanceUnits,'m':DU.MeterDistanceUnits,+         'in':DU.InchDistanceUnits,'inch':DU.InchDistanceUnits,'ft':DU.FootDistanceUnits}+UNITS_NAME  = {0:'mm',1:'cm',2:'m',3:'in',4:'ft'}++def read_current():+    cur = {+      'theme': THEME_NAME.get(gp.userInterfaceTheme, gp.userInterfaceTheme),+      'activeTheme': THEME_NAME.get(gp.activeUserInterfaceTheme, gp.activeUserInterfaceTheme),+      'invertScrollZoom': bool(gp.isZoomDirectionReversed),+      'orbitScheme': ORBIT_NAME.get(gp.panZoomOrbitShortcuts, gp.panZoomOrbitShortcuts),+      'modelingOrientation': ORIENT_NAME.get(gp.defaultModelingOrientation, gp.defaultModelingOrientation),+      'gestureNav': bool(gp.isGestureBasedViewNavigationUsed),+      'cameraPivot': bool(gp.isCameraPivotEnabled),+    }+    try:+        cur['lengthUnit'] = UNITS_NAME.get(design.fusionUnitsManager.distanceDisplayUnits,+                                           design.fusionUnitsManager.distanceDisplayUnits)+    except Exception:+        pass+    return cur++def try_set(obj, attr, cands, want):+    err = None+    for c in cands:+        if c is None: continue+        try:+            setattr(obj, attr, c)+            return {'requested': want, 'ok': True}+        except Exception as e:+            err = str(e)+    return {'requested': want, 'ok': False, 'error': err or 'no valid value'}++reqs = json.loads(__REQS__)+applied = {}+for k, v in reqs.items():+    kv = v if isinstance(v, bool) else str(v).strip().lower()+    if k == 'theme':+        c = THEME.get(kv);  applied[k] = try_set(gp,'userInterfaceTheme', c or [], v) if c else {'requested':v,'ok':False,'error':'unknown theme (use light/darkblue/darkgray/classic/device/dark)'}+    elif k in ('invertScrollZoom','reverseZoom'):+        applied['invertScrollZoom'] = try_set(gp,'isZoomDirectionReversed',[bool(v)],v)+    elif k == 'orbitScheme':+        c = ORBIT.get(kv);  applied[k] = try_set(gp,'panZoomOrbitShortcuts',[c],v) if c is not None else {'requested':v,'ok':False,'error':'unknown orbitScheme'}+    elif k == 'modelingOrientation':+        c = ORIENT.get(kv); applied[k] = try_set(gp,'defaultModelingOrientation',[c],v) if c is not None else {'requested':v,'ok':False,'error':'unknown modelingOrientation (yup/zup)'}+    elif k == 'gestureNav':+        applied[k] = try_set(gp,'isGestureBasedViewNavigationUsed',[bool(v)],v)+    elif k == 'cameraPivot':+        applied[k] = try_set(gp,'isCameraPivotEnabled',[bool(v)],v)+    elif k == 'lengthUnit':+        c = UNITS.get(kv)+        if c is None: applied[k] = {'requested':v,'ok':False,'error':'unknown unit (mm/cm/m/in/ft)'}+        else:+            try: applied[k] = try_set(design.fusionUnitsManager,'distanceDisplayUnits',[c],v)+            except Exception as e: applied[k] = {'requested':v,'ok':False,'error':str(e)}+    else:+        applied[k] = {'requested': v, 'ok': False, 'error': 'unknown preference key'}++result = {'applied': applied, 'current': read_current()}+print(json.dumps(result))
rust/bridge/tests/golden/attach_script.jsonadded+17
@@ -0,0 +1,17 @@+[+ {+  "modelPath": "C:/tmp/LAN7800.step",+  "orient": true,+  "layersOff": [],+  "script": "import adsk.core, adsk.fusion, math\nres={}\nd=adsk.fusion.Design.cast(app.activeProduct); root=d.rootComponent\nim=app.importManager\nim.importToTarget(im.createSTEPImportOptions('C:/tmp/LAN7800.step'), root)\noc=root.occurrences.item(root.occurrences.count-1); bb=oc.boundingBox\ndx=bb.maxPoint.x-bb.minPoint.x; dy=bb.maxPoint.y-bb.minPoint.y; dz=bb.maxPoint.z-bb.minPoint.z\nthin=min(dx,dy,dz); big=max(dx,dy,dz)\ntall_z=(dz>=dx and dz>=dy)\naxis=None\nif (thin < 0.5*big) and not tall_z:\n    axis=(1,0,0) if (dy<=dx and dy<=dz) else ((0,1,0) if (dx<=dy and dx<=dz) else None)\nif axis:\n    mat=oc.transform2.copy(); rot=adsk.core.Matrix3D.create()\n    rot.setToRotation(math.pi/2, adsk.core.Vector3D.create(*axis), adsk.core.Point3D.create(0,0,0))\n    mat.transformBy(rot); oc.transform2=mat\n    d.snapshots.add() if d.snapshots.hasPendingSnapshot else None\nres['dims_mm']=[round(dx*10,2),round(dy*10,2),round(dz*10,2)]\nnames=[]; hidden=[]\ndef _layer(n):\n    n=(n or '').split(':')[0]\n    return n.startswith('Adom.') and n in LAYERS_OFF\ndef _walk(comp, group, hide):\n    for i in range(comp.bRepBodies.count):\n        b=comp.bRepBodies.item(i); names.append((group or '')+'/'+b.name)\n        if hide or _layer(b.name):\n            try:\n                b.isLightBulbOn=False; hidden.append((group or '')+'/'+b.name)\n            except Exception: pass\n    for j in range(comp.occurrences.count):\n        o=comp.occurrences.item(j); on=(o.component.name or o.name).split(':')[0]\n        g=group or (on if on.startswith('Adom.') else '')\n        h=hide or _layer(on)\n        if h and not hide:\n            try: o.isLightBulbOn=False\n            except Exception: pass\n        _walk(o.component, g, h)\nLAYERS_OFF=set([])\ntry:\n    _walk(oc.component, '', False)\nexcept Exception as _e:\n    res['layersError']=str(_e)[:120]\nres['bodies']=names; res['layersHidden']=hidden\nresult=res\n"+ },+ {+  "modelPath": "C:/x/chip.step",+  "orient": false,+  "layersOff": [+   "Adom.Board",+   "Adom.SolderBalls"+  ],+  "script": "import adsk.core, adsk.fusion, math\nres={}\nd=adsk.fusion.Design.cast(app.activeProduct); root=d.rootComponent\nim=app.importManager\nim.importToTarget(im.createSTEPImportOptions('C:/x/chip.step'), root)\noc=root.occurrences.item(root.occurrences.count-1); bb=oc.boundingBox\ndx=bb.maxPoint.x-bb.minPoint.x; dy=bb.maxPoint.y-bb.minPoint.y; dz=bb.maxPoint.z-bb.minPoint.z\naxis=None\nif axis:\n    mat=oc.transform2.copy(); rot=adsk.core.Matrix3D.create()\n    rot.setToRotation(math.pi/2, adsk.core.Vector3D.create(*axis), adsk.core.Point3D.create(0,0,0))\n    mat.transformBy(rot); oc.transform2=mat\n    d.snapshots.add() if d.snapshots.hasPendingSnapshot else None\nres['dims_mm']=[round(dx*10,2),round(dy*10,2),round(dz*10,2)]\nnames=[]; hidden=[]\ndef _layer(n):\n    n=(n or '').split(':')[0]\n    return n.startswith('Adom.') and n in LAYERS_OFF\ndef _walk(comp, group, hide):\n    for i in range(comp.bRepBodies.count):\n        b=comp.bRepBodies.item(i); names.append((group or '')+'/'+b.name)\n        if hide or _layer(b.name):\n            try:\n                b.isLightBulbOn=False; hidden.append((group or '')+'/'+b.name)\n            except Exception: pass\n    for j in range(comp.occurrences.count):\n        o=comp.occurrences.item(j); on=(o.component.name or o.name).split(':')[0]\n        g=group or (on if on.startswith('Adom.') else '')\n        h=hide or _layer(on)\n        if h and not hide:\n            try: o.isLightBulbOn=False\n            except Exception: pass\n        _walk(o.component, g, h)\nLAYERS_OFF=set(['Adom.Board', 'Adom.SolderBalls'])\ntry:\n    _walk(oc.component, '', False)\nexcept Exception as _e:\n    res['layersError']=str(_e)[:120]\nres['bodies']=names; res['layersHidden']=hidden\nresult=res\n"+ }+]\ No newline at end of file
rust/bridge/tests/golden/epg_script.jsonadded+79
@@ -0,0 +1,79 @@+[+ {+  "args": {+   "type": "chip",+   "params": {+    "D": 1.6,+    "E": 0.8,+    "A": 0.45,+    "L": 0.3,+    "L1": 0.2+   },+   "etch": "103",+   "outputStep": "C:/tmp/r0603.step"+  },+  "script": "\nimport sys, glob, os, importlib\nimport adsk.core, adsk.fusion\n\n# Locate EPG across install conventions + versions (NEVER hardcode the webdeploy hash).\n_bases = []\nfor env in ('ProgramFiles', 'ProgramFiles(x86)', 'ProgramW6432', 'LOCALAPPDATA'):\n    root = os.environ.get(env)\n    if root:\n        _bases += glob.glob(os.path.join(root, 'Autodesk', 'webdeploy', 'production', '*',\n                                         'Api', 'InternalAddins', 'ElectronicsPackageGenerator'))\nif not _bases:\n    raise RuntimeError('EPG_NOT_FOUND: ElectronicsPackageGenerator not present in this Fusion install')\nepg_dir = max(_bases, key=os.path.getmtime)\nparent = os.path.dirname(epg_dir)\nif parent not in sys.path:\n    sys.path.insert(0, parent)\n\nmod = importlib.import_module('ElectronicsPackageGenerator.Scripts3d.chip')\n\ndoc = app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)\ndesign = adsk.fusion.Design.cast(app.activeProduct)\nmod.runWithInput({'D': 0.16, 'E': 0.08, 'A': 0.045, 'L': 0.03, 'L1': 0.02}, design)\nroot = design.rootComponent\n\ninv = [{'name': b.name, 'vol': round(b.volume, 6)} for b in root.bRepBodies]\netched = None\nif '103':\n    # FIND THE TOP SURFACE the robust way (John's algorithm, 2026-07-04):\n    # 1. bounding box of the WHOLE chip (all bodies);\n    # 2. only faces whose centroid sits in the TOP 5% band of that bbox count;\n    # 3. among those upward planar faces take the LARGEST AREA (the molded body\n    #    top beats terminal tops that tie it on height);\n    # 4. lay the text out with a 10% margin inside that face.\n    gmin, gmax = 1e9, -1e9\n    for b in root.bRepBodies:\n        bb = b.boundingBox\n        gmin = min(gmin, bb.minPoint.z)\n        gmax = max(gmax, bb.maxPoint.z)\n    band_z = gmax - 0.05 * (gmax - gmin)\n    top_face, top_area = None, -1.0\n    for b in root.bRepBodies:\n        for f in b.faces:\n            if isinstance(f.geometry, adsk.core.Plane) and f.geometry.normal.z > 0.9                     and f.centroid.z >= band_z and f.area > top_area:\n                top_face, top_area = f, f.area\n    if top_face is None:\n        raise RuntimeError('ETCH_NO_TOP_FACE: no upward planar face in the top 5% of the chip bbox')\n    body = top_face.body\n    sk = root.sketches.add(top_face)\n    center = sk.modelToSketchSpace(top_face.centroid)\n    # Measure the face in SKETCH space (model-space bbox axes can be SWAPPED vs\n    # the sketch axes the text lays out in). Project the model bbox corners.\n    bb = top_face.boundingBox\n    p_min = sk.modelToSketchSpace(bb.minPoint)\n    p_max = sk.modelToSketchSpace(bb.maxPoint)\n    face_w = abs(p_max.x - p_min.x)   # extent along sketch-x (the default text baseline)\n    face_h = abs(p_max.y - p_min.y)   # extent along sketch-y\n    # ALWAYS run the text along the LONGEST axis of the top face (most room for\n    # the marking - John's rule, 2026-07-04). If the long axis is sketch-y,\n    # rotate the text 90deg rather than squeezing it onto the short axis.\n    import math as _math\n    rot_deg = 90 if face_h > face_w else 0\n    long_len = max(face_w, face_h)\n    short_len = min(face_w, face_h)\n    w = long_len * 0.80               # 10% margin each side along the long axis\n    box_h_cap = short_len * 0.80      # 10% margin each side across it\n    # multi-line support (e.g. MPN + variant on line 2): fit per-line\n    lines = '103'.split(chr(10))\n    n_lines = max(1, len(lines))\n    max_chars = max(1, max(len(l) for l in lines))\n    # width-aware auto-fit: glyph ~0.75*h wide; line block ~1.35*h per line\n    h = (None / 10.0) if None else         max(0.015, min(box_h_cap / (1.35 * n_lines), w / (0.75 * max_chars)))\n    if rot_deg:\n        c1 = adsk.core.Point3D.create(center.x - box_h_cap/2, center.y - w/2, 0)\n        c2 = adsk.core.Point3D.create(center.x + box_h_cap/2, center.y + w/2, 0)\n    else:\n        c1 = adsk.core.Point3D.create(center.x - w/2, center.y - box_h_cap/2, 0)\n        c2 = adsk.core.Point3D.create(center.x + w/2, center.y + box_h_cap/2, 0)\n    ti = sk.sketchTexts.createInput2('103', h)\n    ti.setAsMultiLine(c1, c2,\n                      adsk.core.HorizontalAlignments.CenterHorizontalAlignment,\n                      adsk.core.VerticalAlignments.MiddleVerticalAlignment, 0)\n    if rot_deg:\n        try:\n            ti.angle = _math.pi / 2.0\n        except Exception:\n            rot_deg = 0  # older API without angle - fall back to unrotated\n    txt = sk.sketchTexts.add(ti)\n    # MEASURE-AND-CORRECT (the margin is a CONTRACT): font metrics vary, so the\n    # 0.75h glyph estimate can under-shoot ('ADOM-A' rendered edge-to-edge). After\n    # placing, measure the text's real bbox; if it busts the 10%-margin box,\n    # recreate at the scaled-down height. Never trust an estimate you can measure.\n    fit_iterations = 0\n    measured_w = None\n    for _pass in range(2):\n        tb = txt.boundingBox\n        t_ext_x = abs(tb.maxPoint.x - tb.minPoint.x)\n        t_ext_y = abs(tb.maxPoint.y - tb.minPoint.y)\n        measured_w = max(t_ext_x, t_ext_y)   # the baseline-axis extent\n        measured_c = min(t_ext_x, t_ext_y)   # the cross-axis extent (line stack)\n        if measured_w <= w and measured_c <= box_h_cap:\n            break\n        scale = min(w / max(measured_w, 1e-6), box_h_cap / max(measured_c, 1e-6)) * 0.95\n        h = max(0.008, h * scale)\n        txt.deleteMe()\n        ti = sk.sketchTexts.createInput2('103', h)\n        ti.setAsMultiLine(c1, c2,\n                          adsk.core.HorizontalAlignments.CenterHorizontalAlignment,\n                          adsk.core.VerticalAlignments.MiddleVerticalAlignment, 0)\n        if rot_deg:\n            try:\n                ti.angle = _math.pi / 2.0\n            except Exception:\n                pass\n        txt = sk.sketchTexts.add(ti)\n        fit_iterations += 1\n    marking_geom = {\n        'chipBBox': {'min': [round(gmin,5), 0, 0], 'maxZ': round(gmax,5)},\n        'chipBBoxZ': {'min': round(gmin,5), 'max': round(gmax,5)},\n        'topBandZ': round(band_z,5),\n        'topFace': {'area': round(top_area,6), 'centroidZ': round(top_face.centroid.z,5),\n                    'sketchExtents': {'x': round(face_w,5), 'y': round(face_h,5)},\n                    'body': body.name},\n        'longAxis': 'sketch-y' if face_h > face_w else 'sketch-x',\n        'rotatedDeg': rot_deg,\n        'textBox': {'c1': [round(c1.x,5), round(c1.y,5)], 'c2': [round(c2.x,5), round(c2.y,5)],\n                    'marginPct': 10},\n        'textHeightMm': round(h*10,4), 'lines': n_lines, 'maxLineChars': max_chars,\n        'heightAuto': not bool(None),\n        'textWidthMeasuredMm': round(measured_w*10,4) if measured_w else None,\n        'fitIterations': fit_iterations,\n        'why': {'band': 'top 5% of whole-chip bbox excludes terminal tops that tie the body',\n                'largestArea': 'molded body top beats small terminal faces in the band',\n                'longAxis': 'text runs along the longest face axis for maximum room',\n                'fit': 'h = min(boxH/(1.35*lines), boxW/(0.75*maxChars)) - glyphs ~0.75h wide'},\n    }\n    if 'raised' == 'engraved':\n        # engraved (sunken) cut - the pre-2026-07-04 default\n        ext_in = root.features.extrudeFeatures.createInput(txt, adsk.fusion.FeatureOperations.CutFeatureOperation)\n        ext_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(-0.003))\n        ext_in.participantBodies = [body]\n        root.features.extrudeFeatures.add(ext_in)\n    else:\n        # RAISED WHITE marking (default): humans need CONTRAST - a thin positive\n        # extrude painted white on the dark body reads like real silkscreen ink,\n        # far better than a same-color emboss. Reuses EPG's own rgb-appearance\n        # utility so the white survives Fusion rendering (+ colored STEP).\n        ext_in = root.features.extrudeFeatures.createInput(txt, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)\n        ext_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(0.003))\n        mark = root.features.extrudeFeatures.add(ext_in)\n        from ElectronicsPackageGenerator.Utilities import addin_utility as _au\n        for i in range(mark.bodies.count):\n            mb = mark.bodies.item(i)\n            mb.name = 'Marking' if i == 0 else 'Marking' + str(i + 1)\n            _au.apply_rgb_appearance(app, design, mb, 255, 255, 255, 'AdomMarkingWhite')\n    etched = '103'\n\nstep_path = None\nif 'C:/tmp/r0603.step':\n    em = design.exportManager\n    opts = em.createSTEPExportOptions('C:/tmp/r0603.step')\n    em.execute(opts)\n    step_path = 'C:/tmp/r0603.step'\n\n# SIDECAR MANIFEST: every setting we picked + WHY + the bboxes we calculated,\n# so a marking refresh (e.g. adding a variant name as a 2nd line) can rework the\n# text without re-deriving anything. Written next to the STEP as <step>.manifest.json.\nmanifest = {\n    'schema': 'adom-fusion-generate-package/1',\n    'bridgeVersion': 'TESTVER',\n    'type': 'chip',\n    'paramsCm': {'D': 0.16, 'E': 0.08, 'A': 0.045, 'L': 0.03, 'L1': 0.02},\n    'paramsNote': 'paramsCm are EPG-native cm (mm inputs were /10)',\n    'marking': ({'text': '103', 'style': 'raised',\n                'depthMm': 0.003 * 10, **marking_geom} if etched else None),\n    'bodies': inv,\n    'outputs': {'step': step_path},\n    'refresh': {\n        'howTo': 'To re-mark (e.g. add a variant on line 2): call fusion_generate_package again '\n                 'with the SAME type+paramsCm (unitsCm:true) and the new multi-line etch text '\n                 '(join lines with a newline). The generator is deterministic, so geometry and '\n                 'placement reproduce exactly; this manifest carries the boxes/height the last '\n                 'run chose for comparison.',\n        'example': {'type': 'chip', 'unitsCm': True, 'params': 'paramsCm from this file',\n                    'etch': ('103' + chr(10) + 'VARIANT') if etched else 'MPN' + chr(10) + 'VARIANT'},\n    },\n}\nmanifest_path = None\nif step_path:\n    manifest_path = step_path + '.manifest.json'\n    import json as _json\n    with open(manifest_path, 'w', encoding='utf-8') as _f:\n        _json.dump(manifest, _f, indent=2)\n\nvp = app.activeViewport\ncam = vp.camera\ncam.isSmoothTransition = False\ncam.target = adsk.core.Point3D.create(0, 0, 0)\ncam.eye = adsk.core.Point3D.create(0.25, -0.35, 0.45)\ncam.upVector = adsk.core.Vector3D.create(0, 0, 1)\ncam.isFitView = True\nvp.camera = cam\nvp.refresh()\n\nresult = {'type': 'chip', 'bodies': inv, 'etched': etched, 'stepPath': step_path,\n           'manifest': manifest, 'manifestPath': manifest_path,\n           'epgDir': epg_dir, 'doc': app.activeDocument.name}\n",+  "errorCode": null+ },+ {+  "args": {+   "type": "soic",+   "params": {+    "A": 1.75,+    "A1": 0.1,+    "b": 0.41,+    "D": 4.9,+    "E": 6.0,+    "E1": 3.9,+    "e": 1.27,+    "L": 0.8,+    "DPins": 8+   },+   "unitsCm": false,+   "etch": "LM358\nADOM-A",+   "etchStyle": "engraved",+   "etchDepthMm": 0.05,+   "etchHeightMm": 0.5+  },+  "script": "\nimport sys, glob, os, importlib\nimport adsk.core, adsk.fusion\n\n# Locate EPG across install conventions + versions (NEVER hardcode the webdeploy hash).\n_bases = []\nfor env in ('ProgramFiles', 'ProgramFiles(x86)', 'ProgramW6432', 'LOCALAPPDATA'):\n    root = os.environ.get(env)\n    if root:\n        _bases += glob.glob(os.path.join(root, 'Autodesk', 'webdeploy', 'production', '*',\n                                         'Api', 'InternalAddins', 'ElectronicsPackageGenerator'))\nif not _bases:\n    raise RuntimeError('EPG_NOT_FOUND: ElectronicsPackageGenerator not present in this Fusion install')\nepg_dir = max(_bases, key=os.path.getmtime)\nparent = os.path.dirname(epg_dir)\nif parent not in sys.path:\n    sys.path.insert(0, parent)\n\nmod = importlib.import_module('ElectronicsPackageGenerator.Scripts3d.soic')\n\ndoc = app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)\ndesign = adsk.fusion.Design.cast(app.activeProduct)\nmod.runWithInput({'A': 0.175, 'A1': 0.01, 'b': 0.040999999999999995, 'D': 0.49000000000000005, 'E': 0.6, 'E1': 0.39, 'e': 0.127, 'L': 0.08, 'DPins': 8}, design)\nroot = design.rootComponent\n\ninv = [{'name': b.name, 'vol': round(b.volume, 6)} for b in root.bRepBodies]\netched = None\nif 'LM358\\nADOM-A':\n    # FIND THE TOP SURFACE the robust way (John's algorithm, 2026-07-04):\n    # 1. bounding box of the WHOLE chip (all bodies);\n    # 2. only faces whose centroid sits in the TOP 5% band of that bbox count;\n    # 3. among those upward planar faces take the LARGEST AREA (the molded body\n    #    top beats terminal tops that tie it on height);\n    # 4. lay the text out with a 10% margin inside that face.\n    gmin, gmax = 1e9, -1e9\n    for b in root.bRepBodies:\n        bb = b.boundingBox\n        gmin = min(gmin, bb.minPoint.z)\n        gmax = max(gmax, bb.maxPoint.z)\n    band_z = gmax - 0.05 * (gmax - gmin)\n    top_face, top_area = None, -1.0\n    for b in root.bRepBodies:\n        for f in b.faces:\n            if isinstance(f.geometry, adsk.core.Plane) and f.geometry.normal.z > 0.9                     and f.centroid.z >= band_z and f.area > top_area:\n                top_face, top_area = f, f.area\n    if top_face is None:\n        raise RuntimeError('ETCH_NO_TOP_FACE: no upward planar face in the top 5% of the chip bbox')\n    body = top_face.body\n    sk = root.sketches.add(top_face)\n    center = sk.modelToSketchSpace(top_face.centroid)\n    # Measure the face in SKETCH space (model-space bbox axes can be SWAPPED vs\n    # the sketch axes the text lays out in). Project the model bbox corners.\n    bb = top_face.boundingBox\n    p_min = sk.modelToSketchSpace(bb.minPoint)\n    p_max = sk.modelToSketchSpace(bb.maxPoint)\n    face_w = abs(p_max.x - p_min.x)   # extent along sketch-x (the default text baseline)\n    face_h = abs(p_max.y - p_min.y)   # extent along sketch-y\n    # ALWAYS run the text along the LONGEST axis of the top face (most room for\n    # the marking - John's rule, 2026-07-04). If the long axis is sketch-y,\n    # rotate the text 90deg rather than squeezing it onto the short axis.\n    import math as _math\n    rot_deg = 90 if face_h > face_w else 0\n    long_len = max(face_w, face_h)\n    short_len = min(face_w, face_h)\n    w = long_len * 0.80               # 10% margin each side along the long axis\n    box_h_cap = short_len * 0.80      # 10% margin each side across it\n    # multi-line support (e.g. MPN + variant on line 2): fit per-line\n    lines = 'LM358\\nADOM-A'.split(chr(10))\n    n_lines = max(1, len(lines))\n    max_chars = max(1, max(len(l) for l in lines))\n    # width-aware auto-fit: glyph ~0.75*h wide; line block ~1.35*h per line\n    h = (0.5 / 10.0) if 0.5 else         max(0.015, min(box_h_cap / (1.35 * n_lines), w / (0.75 * max_chars)))\n    if rot_deg:\n        c1 = adsk.core.Point3D.create(center.x - box_h_cap/2, center.y - w/2, 0)\n        c2 = adsk.core.Point3D.create(center.x + box_h_cap/2, center.y + w/2, 0)\n    else:\n        c1 = adsk.core.Point3D.create(center.x - w/2, center.y - box_h_cap/2, 0)\n        c2 = adsk.core.Point3D.create(center.x + w/2, center.y + box_h_cap/2, 0)\n    ti = sk.sketchTexts.createInput2('LM358\\nADOM-A', h)\n    ti.setAsMultiLine(c1, c2,\n                      adsk.core.HorizontalAlignments.CenterHorizontalAlignment,\n                      adsk.core.VerticalAlignments.MiddleVerticalAlignment, 0)\n    if rot_deg:\n        try:\n            ti.angle = _math.pi / 2.0\n        except Exception:\n            rot_deg = 0  # older API without angle - fall back to unrotated\n    txt = sk.sketchTexts.add(ti)\n    # MEASURE-AND-CORRECT (the margin is a CONTRACT): font metrics vary, so the\n    # 0.75h glyph estimate can under-shoot ('ADOM-A' rendered edge-to-edge). After\n    # placing, measure the text's real bbox; if it busts the 10%-margin box,\n    # recreate at the scaled-down height. Never trust an estimate you can measure.\n    fit_iterations = 0\n    measured_w = None\n    for _pass in range(2):\n        tb = txt.boundingBox\n        t_ext_x = abs(tb.maxPoint.x - tb.minPoint.x)\n        t_ext_y = abs(tb.maxPoint.y - tb.minPoint.y)\n        measured_w = max(t_ext_x, t_ext_y)   # the baseline-axis extent\n        measured_c = min(t_ext_x, t_ext_y)   # the cross-axis extent (line stack)\n        if measured_w <= w and measured_c <= box_h_cap:\n            break\n        scale = min(w / max(measured_w, 1e-6), box_h_cap / max(measured_c, 1e-6)) * 0.95\n        h = max(0.008, h * scale)\n        txt.deleteMe()\n        ti = sk.sketchTexts.createInput2('LM358\\nADOM-A', h)\n        ti.setAsMultiLine(c1, c2,\n                          adsk.core.HorizontalAlignments.CenterHorizontalAlignment,\n                          adsk.core.VerticalAlignments.MiddleVerticalAlignment, 0)\n        if rot_deg:\n            try:\n                ti.angle = _math.pi / 2.0\n            except Exception:\n                pass\n        txt = sk.sketchTexts.add(ti)\n        fit_iterations += 1\n    marking_geom = {\n        'chipBBox': {'min': [round(gmin,5), 0, 0], 'maxZ': round(gmax,5)},\n        'chipBBoxZ': {'min': round(gmin,5), 'max': round(gmax,5)},\n        'topBandZ': round(band_z,5),\n        'topFace': {'area': round(top_area,6), 'centroidZ': round(top_face.centroid.z,5),\n                    'sketchExtents': {'x': round(face_w,5), 'y': round(face_h,5)},\n                    'body': body.name},\n        'longAxis': 'sketch-y' if face_h > face_w else 'sketch-x',\n        'rotatedDeg': rot_deg,\n        'textBox': {'c1': [round(c1.x,5), round(c1.y,5)], 'c2': [round(c2.x,5), round(c2.y,5)],\n                    'marginPct': 10},\n        'textHeightMm': round(h*10,4), 'lines': n_lines, 'maxLineChars': max_chars,\n        'heightAuto': not bool(0.5),\n        'textWidthMeasuredMm': round(measured_w*10,4) if measured_w else None,\n        'fitIterations': fit_iterations,\n        'why': {'band': 'top 5% of whole-chip bbox excludes terminal tops that tie the body',\n                'largestArea': 'molded body top beats small terminal faces in the band',\n                'longAxis': 'text runs along the longest face axis for maximum room',\n                'fit': 'h = min(boxH/(1.35*lines), boxW/(0.75*maxChars)) - glyphs ~0.75h wide'},\n    }\n    if 'engraved' == 'engraved':\n        # engraved (sunken) cut - the pre-2026-07-04 default\n        ext_in = root.features.extrudeFeatures.createInput(txt, adsk.fusion.FeatureOperations.CutFeatureOperation)\n        ext_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(-0.005))\n        ext_in.participantBodies = [body]\n        root.features.extrudeFeatures.add(ext_in)\n    else:\n        # RAISED WHITE marking (default): humans need CONTRAST - a thin positive\n        # extrude painted white on the dark body reads like real silkscreen ink,\n        # far better than a same-color emboss. Reuses EPG's own rgb-appearance\n        # utility so the white survives Fusion rendering (+ colored STEP).\n        ext_in = root.features.extrudeFeatures.createInput(txt, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)\n        ext_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(0.005))\n        mark = root.features.extrudeFeatures.add(ext_in)\n        from ElectronicsPackageGenerator.Utilities import addin_utility as _au\n        for i in range(mark.bodies.count):\n            mb = mark.bodies.item(i)\n            mb.name = 'Marking' if i == 0 else 'Marking' + str(i + 1)\n            _au.apply_rgb_appearance(app, design, mb, 255, 255, 255, 'AdomMarkingWhite')\n    etched = 'LM358\\nADOM-A'\n\nstep_path = None\nif '':\n    em = design.exportManager\n    opts = em.createSTEPExportOptions('')\n    em.execute(opts)\n    step_path = ''\n\n# SIDECAR MANIFEST: every setting we picked + WHY + the bboxes we calculated,\n# so a marking refresh (e.g. adding a variant name as a 2nd line) can rework the\n# text without re-deriving anything. Written next to the STEP as <step>.manifest.json.\nmanifest = {\n    'schema': 'adom-fusion-generate-package/1',\n    'bridgeVersion': 'TESTVER',\n    'type': 'soic',\n    'paramsCm': {'A': 0.175, 'A1': 0.01, 'b': 0.040999999999999995, 'D': 0.49000000000000005, 'E': 0.6, 'E1': 0.39, 'e': 0.127, 'L': 0.08, 'DPins': 8},\n    'paramsNote': 'paramsCm are EPG-native cm (mm inputs were /10)',\n    'marking': ({'text': 'LM358\\nADOM-A', 'style': 'engraved',\n                'depthMm': 0.005 * 10, **marking_geom} if etched else None),\n    'bodies': inv,\n    'outputs': {'step': step_path},\n    'refresh': {\n        'howTo': 'To re-mark (e.g. add a variant on line 2): call fusion_generate_package again '\n                 'with the SAME type+paramsCm (unitsCm:true) and the new multi-line etch text '\n                 '(join lines with a newline). The generator is deterministic, so geometry and '\n                 'placement reproduce exactly; this manifest carries the boxes/height the last '\n                 'run chose for comparison.',\n        'example': {'type': 'soic', 'unitsCm': True, 'params': 'paramsCm from this file',\n                    'etch': ('LM358\\nADOM-A' + chr(10) + 'VARIANT') if etched else 'MPN' + chr(10) + 'VARIANT'},\n    },\n}\nmanifest_path = None\nif step_path:\n    manifest_path = step_path + '.manifest.json'\n    import json as _json\n    with open(manifest_path, 'w', encoding='utf-8') as _f:\n        _json.dump(manifest, _f, indent=2)\n\nvp = app.activeViewport\ncam = vp.camera\ncam.isSmoothTransition = False\ncam.target = adsk.core.Point3D.create(0, 0, 0)\ncam.eye = adsk.core.Point3D.create(0.25, -0.35, 0.45)\ncam.upVector = adsk.core.Vector3D.create(0, 0, 1)\ncam.isFitView = True\nvp.camera = cam\nvp.refresh()\n\nresult = {'type': 'soic', 'bodies': inv, 'etched': etched, 'stepPath': step_path,\n           'manifest': manifest, 'manifestPath': manifest_path,\n           'epgDir': epg_dir, 'doc': app.activeDocument.name}\n",+  "errorCode": null+ },+ {+  "args": {+   "type": "qfn",+   "params": {+    "D": 0.5,+    "E": 0.5,+    "DPins": 4,+    "EPins": 4,+    "color_r": 30+   },+   "unitsCm": true,+   "etch": "it's \"q\"",+   "etchHeightMm": 1+  },+  "script": "\nimport sys, glob, os, importlib\nimport adsk.core, adsk.fusion\n\n# Locate EPG across install conventions + versions (NEVER hardcode the webdeploy hash).\n_bases = []\nfor env in ('ProgramFiles', 'ProgramFiles(x86)', 'ProgramW6432', 'LOCALAPPDATA'):\n    root = os.environ.get(env)\n    if root:\n        _bases += glob.glob(os.path.join(root, 'Autodesk', 'webdeploy', 'production', '*',\n                                         'Api', 'InternalAddins', 'ElectronicsPackageGenerator'))\nif not _bases:\n    raise RuntimeError('EPG_NOT_FOUND: ElectronicsPackageGenerator not present in this Fusion install')\nepg_dir = max(_bases, key=os.path.getmtime)\nparent = os.path.dirname(epg_dir)\nif parent not in sys.path:\n    sys.path.insert(0, parent)\n\nmod = importlib.import_module('ElectronicsPackageGenerator.Scripts3d.qfn')\n\ndoc = app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)\ndesign = adsk.fusion.Design.cast(app.activeProduct)\nmod.runWithInput({'D': 0.5, 'E': 0.5, 'DPins': 4, 'EPins': 4, 'color_r': 30}, design)\nroot = design.rootComponent\n\ninv = [{'name': b.name, 'vol': round(b.volume, 6)} for b in root.bRepBodies]\netched = None\nif 'it\\'s \"q\"':\n    # FIND THE TOP SURFACE the robust way (John's algorithm, 2026-07-04):\n    # 1. bounding box of the WHOLE chip (all bodies);\n    # 2. only faces whose centroid sits in the TOP 5% band of that bbox count;\n    # 3. among those upward planar faces take the LARGEST AREA (the molded body\n    #    top beats terminal tops that tie it on height);\n    # 4. lay the text out with a 10% margin inside that face.\n    gmin, gmax = 1e9, -1e9\n    for b in root.bRepBodies:\n        bb = b.boundingBox\n        gmin = min(gmin, bb.minPoint.z)\n        gmax = max(gmax, bb.maxPoint.z)\n    band_z = gmax - 0.05 * (gmax - gmin)\n    top_face, top_area = None, -1.0\n    for b in root.bRepBodies:\n        for f in b.faces:\n            if isinstance(f.geometry, adsk.core.Plane) and f.geometry.normal.z > 0.9                     and f.centroid.z >= band_z and f.area > top_area:\n                top_face, top_area = f, f.area\n    if top_face is None:\n        raise RuntimeError('ETCH_NO_TOP_FACE: no upward planar face in the top 5% of the chip bbox')\n    body = top_face.body\n    sk = root.sketches.add(top_face)\n    center = sk.modelToSketchSpace(top_face.centroid)\n    # Measure the face in SKETCH space (model-space bbox axes can be SWAPPED vs\n    # the sketch axes the text lays out in). Project the model bbox corners.\n    bb = top_face.boundingBox\n    p_min = sk.modelToSketchSpace(bb.minPoint)\n    p_max = sk.modelToSketchSpace(bb.maxPoint)\n    face_w = abs(p_max.x - p_min.x)   # extent along sketch-x (the default text baseline)\n    face_h = abs(p_max.y - p_min.y)   # extent along sketch-y\n    # ALWAYS run the text along the LONGEST axis of the top face (most room for\n    # the marking - John's rule, 2026-07-04). If the long axis is sketch-y,\n    # rotate the text 90deg rather than squeezing it onto the short axis.\n    import math as _math\n    rot_deg = 90 if face_h > face_w else 0\n    long_len = max(face_w, face_h)\n    short_len = min(face_w, face_h)\n    w = long_len * 0.80               # 10% margin each side along the long axis\n    box_h_cap = short_len * 0.80      # 10% margin each side across it\n    # multi-line support (e.g. MPN + variant on line 2): fit per-line\n    lines = 'it\\'s \"q\"'.split(chr(10))\n    n_lines = max(1, len(lines))\n    max_chars = max(1, max(len(l) for l in lines))\n    # width-aware auto-fit: glyph ~0.75*h wide; line block ~1.35*h per line\n    h = (1 / 10.0) if 1 else         max(0.015, min(box_h_cap / (1.35 * n_lines), w / (0.75 * max_chars)))\n    if rot_deg:\n        c1 = adsk.core.Point3D.create(center.x - box_h_cap/2, center.y - w/2, 0)\n        c2 = adsk.core.Point3D.create(center.x + box_h_cap/2, center.y + w/2, 0)\n    else:\n        c1 = adsk.core.Point3D.create(center.x - w/2, center.y - box_h_cap/2, 0)\n        c2 = adsk.core.Point3D.create(center.x + w/2, center.y + box_h_cap/2, 0)\n    ti = sk.sketchTexts.createInput2('it\\'s \"q\"', h)\n    ti.setAsMultiLine(c1, c2,\n                      adsk.core.HorizontalAlignments.CenterHorizontalAlignment,\n                      adsk.core.VerticalAlignments.MiddleVerticalAlignment, 0)\n    if rot_deg:\n        try:\n            ti.angle = _math.pi / 2.0\n        except Exception:\n            rot_deg = 0  # older API without angle - fall back to unrotated\n    txt = sk.sketchTexts.add(ti)\n    # MEASURE-AND-CORRECT (the margin is a CONTRACT): font metrics vary, so the\n    # 0.75h glyph estimate can under-shoot ('ADOM-A' rendered edge-to-edge). After\n    # placing, measure the text's real bbox; if it busts the 10%-margin box,\n    # recreate at the scaled-down height. Never trust an estimate you can measure.\n    fit_iterations = 0\n    measured_w = None\n    for _pass in range(2):\n        tb = txt.boundingBox\n        t_ext_x = abs(tb.maxPoint.x - tb.minPoint.x)\n        t_ext_y = abs(tb.maxPoint.y - tb.minPoint.y)\n        measured_w = max(t_ext_x, t_ext_y)   # the baseline-axis extent\n        measured_c = min(t_ext_x, t_ext_y)   # the cross-axis extent (line stack)\n        if measured_w <= w and measured_c <= box_h_cap:\n            break\n        scale = min(w / max(measured_w, 1e-6), box_h_cap / max(measured_c, 1e-6)) * 0.95\n        h = max(0.008, h * scale)\n        txt.deleteMe()\n        ti = sk.sketchTexts.createInput2('it\\'s \"q\"', h)\n        ti.setAsMultiLine(c1, c2,\n                          adsk.core.HorizontalAlignments.CenterHorizontalAlignment,\n                          adsk.core.VerticalAlignments.MiddleVerticalAlignment, 0)\n        if rot_deg:\n            try:\n                ti.angle = _math.pi / 2.0\n            except Exception:\n                pass\n        txt = sk.sketchTexts.add(ti)\n        fit_iterations += 1\n    marking_geom = {\n        'chipBBox': {'min': [round(gmin,5), 0, 0], 'maxZ': round(gmax,5)},\n        'chipBBoxZ': {'min': round(gmin,5), 'max': round(gmax,5)},\n        'topBandZ': round(band_z,5),\n        'topFace': {'area': round(top_area,6), 'centroidZ': round(top_face.centroid.z,5),\n                    'sketchExtents': {'x': round(face_w,5), 'y': round(face_h,5)},\n                    'body': body.name},\n        'longAxis': 'sketch-y' if face_h > face_w else 'sketch-x',\n        'rotatedDeg': rot_deg,\n        'textBox': {'c1': [round(c1.x,5), round(c1.y,5)], 'c2': [round(c2.x,5), round(c2.y,5)],\n                    'marginPct': 10},\n        'textHeightMm': round(h*10,4), 'lines': n_lines, 'maxLineChars': max_chars,\n        'heightAuto': not bool(1),\n        'textWidthMeasuredMm': round(measured_w*10,4) if measured_w else None,\n        'fitIterations': fit_iterations,\n        'why': {'band': 'top 5% of whole-chip bbox excludes terminal tops that tie the body',\n                'largestArea': 'molded body top beats small terminal faces in the band',\n                'longAxis': 'text runs along the longest face axis for maximum room',\n                'fit': 'h = min(boxH/(1.35*lines), boxW/(0.75*maxChars)) - glyphs ~0.75h wide'},\n    }\n    if 'raised' == 'engraved':\n        # engraved (sunken) cut - the pre-2026-07-04 default\n        ext_in = root.features.extrudeFeatures.createInput(txt, adsk.fusion.FeatureOperations.CutFeatureOperation)\n        ext_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(-0.003))\n        ext_in.participantBodies = [body]\n        root.features.extrudeFeatures.add(ext_in)\n    else:\n        # RAISED WHITE marking (default): humans need CONTRAST - a thin positive\n        # extrude painted white on the dark body reads like real silkscreen ink,\n        # far better than a same-color emboss. Reuses EPG's own rgb-appearance\n        # utility so the white survives Fusion rendering (+ colored STEP).\n        ext_in = root.features.extrudeFeatures.createInput(txt, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)\n        ext_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(0.003))\n        mark = root.features.extrudeFeatures.add(ext_in)\n        from ElectronicsPackageGenerator.Utilities import addin_utility as _au\n        for i in range(mark.bodies.count):\n            mb = mark.bodies.item(i)\n            mb.name = 'Marking' if i == 0 else 'Marking' + str(i + 1)\n            _au.apply_rgb_appearance(app, design, mb, 255, 255, 255, 'AdomMarkingWhite')\n    etched = 'it\\'s \"q\"'\n\nstep_path = None\nif '':\n    em = design.exportManager\n    opts = em.createSTEPExportOptions('')\n    em.execute(opts)\n    step_path = ''\n\n# SIDECAR MANIFEST: every setting we picked + WHY + the bboxes we calculated,\n# so a marking refresh (e.g. adding a variant name as a 2nd line) can rework the\n# text without re-deriving anything. Written next to the STEP as <step>.manifest.json.\nmanifest = {\n    'schema': 'adom-fusion-generate-package/1',\n    'bridgeVersion': 'TESTVER',\n    'type': 'qfn',\n    'paramsCm': {'D': 0.5, 'E': 0.5, 'DPins': 4, 'EPins': 4, 'color_r': 30},\n    'paramsNote': 'paramsCm are EPG-native cm (mm inputs were /10)',\n    'marking': ({'text': 'it\\'s \"q\"', 'style': 'raised',\n                'depthMm': 0.003 * 10, **marking_geom} if etched else None),\n    'bodies': inv,\n    'outputs': {'step': step_path},\n    'refresh': {\n        'howTo': 'To re-mark (e.g. add a variant on line 2): call fusion_generate_package again '\n                 'with the SAME type+paramsCm (unitsCm:true) and the new multi-line etch text '\n                 '(join lines with a newline). The generator is deterministic, so geometry and '\n                 'placement reproduce exactly; this manifest carries the boxes/height the last '\n                 'run chose for comparison.',\n        'example': {'type': 'qfn', 'unitsCm': True, 'params': 'paramsCm from this file',\n                    'etch': ('it\\'s \"q\"' + chr(10) + 'VARIANT') if etched else 'MPN' + chr(10) + 'VARIANT'},\n    },\n}\nmanifest_path = None\nif step_path:\n    manifest_path = step_path + '.manifest.json'\n    import json as _json\n    with open(manifest_path, 'w', encoding='utf-8') as _f:\n        _json.dump(manifest, _f, indent=2)\n\nvp = app.activeViewport\ncam = vp.camera\ncam.isSmoothTransition = False\ncam.target = adsk.core.Point3D.create(0, 0, 0)\ncam.eye = adsk.core.Point3D.create(0.25, -0.35, 0.45)\ncam.upVector = adsk.core.Vector3D.create(0, 0, 1)\ncam.isFitView = True\nvp.camera = cam\nvp.refresh()\n\nresult = {'type': 'qfn', 'bodies': inv, 'etched': etched, 'stepPath': step_path,\n           'manifest': manifest, 'manifestPath': manifest_path,\n           'epgDir': epg_dir, 'doc': app.activeDocument.name}\n",+  "errorCode": null+ },+ {+  "args": {+   "type": "chip",+   "params": {+    "D": 3,+    "E": 1e-05,+    "A": 1.2345678901234568e+16+   },+   "etch": ""+  },+  "script": "\nimport sys, glob, os, importlib\nimport adsk.core, adsk.fusion\n\n# Locate EPG across install conventions + versions (NEVER hardcode the webdeploy hash).\n_bases = []\nfor env in ('ProgramFiles', 'ProgramFiles(x86)', 'ProgramW6432', 'LOCALAPPDATA'):\n    root = os.environ.get(env)\n    if root:\n        _bases += glob.glob(os.path.join(root, 'Autodesk', 'webdeploy', 'production', '*',\n                                         'Api', 'InternalAddins', 'ElectronicsPackageGenerator'))\nif not _bases:\n    raise RuntimeError('EPG_NOT_FOUND: ElectronicsPackageGenerator not present in this Fusion install')\nepg_dir = max(_bases, key=os.path.getmtime)\nparent = os.path.dirname(epg_dir)\nif parent not in sys.path:\n    sys.path.insert(0, parent)\n\nmod = importlib.import_module('ElectronicsPackageGenerator.Scripts3d.chip')\n\ndoc = app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)\ndesign = adsk.fusion.Design.cast(app.activeProduct)\nmod.runWithInput({'D': 0.3, 'E': 1.0000000000000002e-06, 'A': 1234567890123456.8}, design)\nroot = design.rootComponent\n\ninv = [{'name': b.name, 'vol': round(b.volume, 6)} for b in root.bRepBodies]\netched = None\nif '':\n    # FIND THE TOP SURFACE the robust way (John's algorithm, 2026-07-04):\n    # 1. bounding box of the WHOLE chip (all bodies);\n    # 2. only faces whose centroid sits in the TOP 5% band of that bbox count;\n    # 3. among those upward planar faces take the LARGEST AREA (the molded body\n    #    top beats terminal tops that tie it on height);\n    # 4. lay the text out with a 10% margin inside that face.\n    gmin, gmax = 1e9, -1e9\n    for b in root.bRepBodies:\n        bb = b.boundingBox\n        gmin = min(gmin, bb.minPoint.z)\n        gmax = max(gmax, bb.maxPoint.z)\n    band_z = gmax - 0.05 * (gmax - gmin)\n    top_face, top_area = None, -1.0\n    for b in root.bRepBodies:\n        for f in b.faces:\n            if isinstance(f.geometry, adsk.core.Plane) and f.geometry.normal.z > 0.9                     and f.centroid.z >= band_z and f.area > top_area:\n                top_face, top_area = f, f.area\n    if top_face is None:\n        raise RuntimeError('ETCH_NO_TOP_FACE: no upward planar face in the top 5% of the chip bbox')\n    body = top_face.body\n    sk = root.sketches.add(top_face)\n    center = sk.modelToSketchSpace(top_face.centroid)\n    # Measure the face in SKETCH space (model-space bbox axes can be SWAPPED vs\n    # the sketch axes the text lays out in). Project the model bbox corners.\n    bb = top_face.boundingBox\n    p_min = sk.modelToSketchSpace(bb.minPoint)\n    p_max = sk.modelToSketchSpace(bb.maxPoint)\n    face_w = abs(p_max.x - p_min.x)   # extent along sketch-x (the default text baseline)\n    face_h = abs(p_max.y - p_min.y)   # extent along sketch-y\n    # ALWAYS run the text along the LONGEST axis of the top face (most room for\n    # the marking - John's rule, 2026-07-04). If the long axis is sketch-y,\n    # rotate the text 90deg rather than squeezing it onto the short axis.\n    import math as _math\n    rot_deg = 90 if face_h > face_w else 0\n    long_len = max(face_w, face_h)\n    short_len = min(face_w, face_h)\n    w = long_len * 0.80               # 10% margin each side along the long axis\n    box_h_cap = short_len * 0.80      # 10% margin each side across it\n    # multi-line support (e.g. MPN + variant on line 2): fit per-line\n    lines = ''.split(chr(10))\n    n_lines = max(1, len(lines))\n    max_chars = max(1, max(len(l) for l in lines))\n    # width-aware auto-fit: glyph ~0.75*h wide; line block ~1.35*h per line\n    h = (None / 10.0) if None else         max(0.015, min(box_h_cap / (1.35 * n_lines), w / (0.75 * max_chars)))\n    if rot_deg:\n        c1 = adsk.core.Point3D.create(center.x - box_h_cap/2, center.y - w/2, 0)\n        c2 = adsk.core.Point3D.create(center.x + box_h_cap/2, center.y + w/2, 0)\n    else:\n        c1 = adsk.core.Point3D.create(center.x - w/2, center.y - box_h_cap/2, 0)\n        c2 = adsk.core.Point3D.create(center.x + w/2, center.y + box_h_cap/2, 0)\n    ti = sk.sketchTexts.createInput2('', h)\n    ti.setAsMultiLine(c1, c2,\n                      adsk.core.HorizontalAlignments.CenterHorizontalAlignment,\n                      adsk.core.VerticalAlignments.MiddleVerticalAlignment, 0)\n    if rot_deg:\n        try:\n            ti.angle = _math.pi / 2.0\n        except Exception:\n            rot_deg = 0  # older API without angle - fall back to unrotated\n    txt = sk.sketchTexts.add(ti)\n    # MEASURE-AND-CORRECT (the margin is a CONTRACT): font metrics vary, so the\n    # 0.75h glyph estimate can under-shoot ('ADOM-A' rendered edge-to-edge). After\n    # placing, measure the text's real bbox; if it busts the 10%-margin box,\n    # recreate at the scaled-down height. Never trust an estimate you can measure.\n    fit_iterations = 0\n    measured_w = None\n    for _pass in range(2):\n        tb = txt.boundingBox\n        t_ext_x = abs(tb.maxPoint.x - tb.minPoint.x)\n        t_ext_y = abs(tb.maxPoint.y - tb.minPoint.y)\n        measured_w = max(t_ext_x, t_ext_y)   # the baseline-axis extent\n        measured_c = min(t_ext_x, t_ext_y)   # the cross-axis extent (line stack)\n        if measured_w <= w and measured_c <= box_h_cap:\n            break\n        scale = min(w / max(measured_w, 1e-6), box_h_cap / max(measured_c, 1e-6)) * 0.95\n        h = max(0.008, h * scale)\n        txt.deleteMe()\n        ti = sk.sketchTexts.createInput2('', h)\n        ti.setAsMultiLine(c1, c2,\n                          adsk.core.HorizontalAlignments.CenterHorizontalAlignment,\n                          adsk.core.VerticalAlignments.MiddleVerticalAlignment, 0)\n        if rot_deg:\n            try:\n                ti.angle = _math.pi / 2.0\n            except Exception:\n                pass\n        txt = sk.sketchTexts.add(ti)\n        fit_iterations += 1\n    marking_geom = {\n        'chipBBox': {'min': [round(gmin,5), 0, 0], 'maxZ': round(gmax,5)},\n        'chipBBoxZ': {'min': round(gmin,5), 'max': round(gmax,5)},\n        'topBandZ': round(band_z,5),\n        'topFace': {'area': round(top_area,6), 'centroidZ': round(top_face.centroid.z,5),\n                    'sketchExtents': {'x': round(face_w,5), 'y': round(face_h,5)},\n                    'body': body.name},\n        'longAxis': 'sketch-y' if face_h > face_w else 'sketch-x',\n        'rotatedDeg': rot_deg,\n        'textBox': {'c1': [round(c1.x,5), round(c1.y,5)], 'c2': [round(c2.x,5), round(c2.y,5)],\n                    'marginPct': 10},\n        'textHeightMm': round(h*10,4), 'lines': n_lines, 'maxLineChars': max_chars,\n        'heightAuto': not bool(None),\n        'textWidthMeasuredMm': round(measured_w*10,4) if measured_w else None,\n        'fitIterations': fit_iterations,\n        'why': {'band': 'top 5% of whole-chip bbox excludes terminal tops that tie the body',\n                'largestArea': 'molded body top beats small terminal faces in the band',\n                'longAxis': 'text runs along the longest face axis for maximum room',\n                'fit': 'h = min(boxH/(1.35*lines), boxW/(0.75*maxChars)) - glyphs ~0.75h wide'},\n    }\n    if 'raised' == 'engraved':\n        # engraved (sunken) cut - the pre-2026-07-04 default\n        ext_in = root.features.extrudeFeatures.createInput(txt, adsk.fusion.FeatureOperations.CutFeatureOperation)\n        ext_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(-0.003))\n        ext_in.participantBodies = [body]\n        root.features.extrudeFeatures.add(ext_in)\n    else:\n        # RAISED WHITE marking (default): humans need CONTRAST - a thin positive\n        # extrude painted white on the dark body reads like real silkscreen ink,\n        # far better than a same-color emboss. Reuses EPG's own rgb-appearance\n        # utility so the white survives Fusion rendering (+ colored STEP).\n        ext_in = root.features.extrudeFeatures.createInput(txt, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)\n        ext_in.setDistanceExtent(False, adsk.core.ValueInput.createByReal(0.003))\n        mark = root.features.extrudeFeatures.add(ext_in)\n        from ElectronicsPackageGenerator.Utilities import addin_utility as _au\n        for i in range(mark.bodies.count):\n            mb = mark.bodies.item(i)\n            mb.name = 'Marking' if i == 0 else 'Marking' + str(i + 1)\n            _au.apply_rgb_appearance(app, design, mb, 255, 255, 255, 'AdomMarkingWhite')\n    etched = ''\n\nstep_path = None\nif '':\n    em = design.exportManager\n    opts = em.createSTEPExportOptions('')\n    em.execute(opts)\n    step_path = ''\n\n# SIDECAR MANIFEST: every setting we picked + WHY + the bboxes we calculated,\n# so a marking refresh (e.g. adding a variant name as a 2nd line) can rework the\n# text without re-deriving anything. Written next to the STEP as <step>.manifest.json.\nmanifest = {\n    'schema': 'adom-fusion-generate-package/1',\n    'bridgeVersion': 'TESTVER',\n    'type': 'chip',\n    'paramsCm': {'D': 0.3, 'E': 1.0000000000000002e-06, 'A': 1234567890123456.8},\n    'paramsNote': 'paramsCm are EPG-native cm (mm inputs were /10)',\n    'marking': ({'text': '', 'style': 'raised',\n                'depthMm': 0.003 * 10, **marking_geom} if etched else None),\n    'bodies': inv,\n    'outputs': {'step': step_path},\n    'refresh': {\n        'howTo': 'To re-mark (e.g. add a variant on line 2): call fusion_generate_package again '\n                 'with the SAME type+paramsCm (unitsCm:true) and the new multi-line etch text '\n                 '(join lines with a newline). The generator is deterministic, so geometry and '\n                 'placement reproduce exactly; this manifest carries the boxes/height the last '\n                 'run chose for comparison.',\n        'example': {'type': 'chip', 'unitsCm': True, 'params': 'paramsCm from this file',\n                    'etch': ('' + chr(10) + 'VARIANT') if etched else 'MPN' + chr(10) + 'VARIANT'},\n    },\n}\nmanifest_path = None\nif step_path:\n    manifest_path = step_path + '.manifest.json'\n    import json as _json\n    with open(manifest_path, 'w', encoding='utf-8') as _f:\n        _json.dump(manifest, _f, indent=2)\n\nvp = app.activeViewport\ncam = vp.camera\ncam.isSmoothTransition = False\ncam.target = adsk.core.Point3D.create(0, 0, 0)\ncam.eye = adsk.core.Point3D.create(0.25, -0.35, 0.45)\ncam.upVector = adsk.core.Vector3D.create(0, 0, 1)\ncam.isFitView = True\nvp.camera = cam\nvp.refresh()\n\nresult = {'type': 'chip', 'bodies': inv, 'etched': etched, 'stepPath': step_path,\n           'manifest': manifest, 'manifestPath': manifest_path,\n           'epgDir': epg_dir, 'doc': app.activeDocument.name}\n",+  "errorCode": null+ },+ {+  "args": {+   "type": "bogus",+   "params": {}+  },+  "script": null,+  "errorCode": "unknown_package_type"+ }+]\ No newline at end of file
rust/bridge/tests/golden/make3d_script.jsonadded+26
@@ -0,0 +1,26 @@+[+ {+  "modelPath": "C:/tmp/LAN7800.step",+  "orient": true,+  "pin1": [+   -3.5,+   2.75+  ],+  "layersOff": [],+  "task": "Demo_Board",+  "name": "LAN7800_3d",+  "script": "import adsk.core, adsk.fusion, math\napp=adsk.core.Application.get(); doc=app.activeDocument\nd=adsk.fusion.Design.cast(app.activeProduct); root=d.rootComponent\nim=app.importManager\nim.importToTarget(im.createSTEPImportOptions('C:/tmp/LAN7800.step'), root)\noc=root.occurrences.item(root.occurrences.count-1); bb=oc.boundingBox\ndx=bb.maxPoint.x-bb.minPoint.x; dy=bb.maxPoint.y-bb.minPoint.y; dz=bb.maxPoint.z-bb.minPoint.z\nthin=min(dx,dy,dz); big=max(dx,dy,dz)\ntall_z=(dz>=dx and dz>=dy)\nis_flat=(thin < 0.5*big)\naxis=None\nif is_flat and not tall_z:\n axis=(1,0,0) if (dy<=dx and dy<=dz) else ((0,1,0) if (dx<=dy and dx<=dz) else None)\nif axis:\n mat=oc.transform2.copy(); r=adsk.core.Matrix3D.create()\n r.setToRotation(math.pi/2, adsk.core.Vector3D.create(*axis), adsk.core.Point3D.create(0,0,0))\n mat.transformBy(r); oc.transform2=mat\nPIN1=(-0.35, 0.275)\nres_pin1={'pad1_mm': [-3.5,2.75], 'mark_mm': None, 'rotatedDeg': 0, 'status': 'unchecked'}\ndef _mark(occ):\n    bb2=occ.boundingBox; zmax=bb2.maxPoint.z; best=None\n    def _w(comp, depth):\n        nonlocal best\n        if depth>6: return\n        for i in range(comp.bRepBodies.count):\n            b=comp.bRepBodies.item(i)\n            try: vol=b.volume\n            except Exception: vol=0\n            if vol*1000 < 5: continue\n            for e in b.edges:\n                try:\n                    g=e.geometry\n                    if g.objectType not in (adsk.core.Circle3D.classType(), adsk.core.Arc3D.classType()): continue\n                    c=g.center\n                    if abs(c.z-zmax)>0.03 or g.radius>0.1: continue\n                    score=abs(c.x)+abs(c.y)\n                    if best is None or score>best[0]: best=(score,c.x,c.y)\n                except Exception: pass\n        for j in range(comp.occurrences.count): _w(comp.occurrences.item(j).component, depth+1)\n    _w(occ.component, 0)\n    return None if best is None else (best[1],best[2])\ntry:\n    mk=_mark(oc)\n    if mk: res_pin1['mark_mm']=[round(mk[0]*10,2), round(mk[1]*10,2)]\n    if mk and PIN1:\n        import math as _m\n        want=_m.atan2(PIN1[1],PIN1[0]); have=_m.atan2(mk[1],mk[0])\n        k=int(round(((want-have)/(_m.pi/2)))) % 4\n        if k:\n            mat=oc.transform2.copy(); r=adsk.core.Matrix3D.create()\n            r.setToRotation(k*_m.pi/2, adsk.core.Vector3D.create(0,0,1), adsk.core.Point3D.create(0,0,0))\n            mat.transformBy(r); oc.transform2=mat\n            res_pin1['rotatedDeg']=k*90\n        res_pin1['status']='rotated' if k else 'aligned'\n    elif PIN1: res_pin1['status']='no_mark_on_chip'\n    else: res_pin1['status']='no_pad1_in_lbr'\nexcept Exception as _e: res_pin1['status']='error: '+str(_e)[:80]\ntry:\n app.activeViewport.fit()\nexcept: pass\ndef _sub(p,nm):\n import time as _ts\n for _try in range(4):\n  for i in range(p.dataFolders.count):\n   if str(p.dataFolders.item(i).name).lower()==str(nm).lower(): return p.dataFolders.item(i)\n  try: return p.dataFolders.add(nm)\n  except Exception as _fe:\n   if 'CB_NAE' not in str(_fe) and 'same name' not in str(_fe): raise\n   adsk.doEvents(); _ts.sleep(2.0)\n raise RuntimeError('cloud folder %s exists but cannot be resolved' % nm)\nres={}\nnames=[]; hidden=[]\ndef _layer(n):\n    n=(n or '').split(':')[0]\n    return n.startswith('Adom.') and n in LAYERS_OFF\ndef _walk(comp, group, hide):\n    for i in range(comp.bRepBodies.count):\n        b=comp.bRepBodies.item(i); names.append((group or '')+'/'+b.name)\n        if hide or _layer(b.name):\n            try:\n                b.isLightBulbOn=False; hidden.append((group or '')+'/'+b.name)\n            except Exception: pass\n    for j in range(comp.occurrences.count):\n        o=comp.occurrences.item(j); on=(o.component.name or o.name).split(':')[0]\n        g=group or (on if on.startswith('Adom.') else '')\n        h=hide or _layer(on)\n        if h and not hide:\n            try: o.isLightBulbOn=False\n            except Exception: pass\n        _walk(o.component, g, h)\nLAYERS_OFF=set([])\ntry:\n    _walk(oc.component, '', False)\nexcept Exception as _e:\n    res['layersError']=str(_e)[:120]\nres['bodies']=names; res['layersHidden']=hidden\nres['pin1']=res_pin1\nproj=None\ntry: proj=app.data.activeProject\nexcept Exception as e: res['projErr']=str(e)[:60]\nif not proj:\n try:\n  hubs=app.data.dataHubs\n  for hi in range(hubs.count):\n   ps=hubs.item(hi).dataProjects\n   for pj2 in range(ps.count):\n    p2=ps.item(pj2)\n    ok=False\n    try: ok=(p2.id=='a.YnVzaW5lc3M6YWRvbTMjMjAyMzExMjk3MDM5NjAzMzE')\n    except Exception: ok=False\n    if not ok:\n     try: ok=(p2.name=='Main')\n     except Exception: continue\n    if ok: proj=p2; break\n   if proj: break\n except Exception as e: res['projErr']=str(e)[:60]\nif not proj:\n try:\n  hubs=app.data.dataHubs\n  for hi in range(hubs.count):\n   ps=hubs.item(hi).dataProjects\n   for pj2 in range(ps.count):\n    try:\n     p2=ps.item(pj2); p2.rootFolder\n     proj=p2; break\n    except Exception: continue\n   if proj: break\n  if not proj:\n   for hi in range(hubs.count):\n    try:\n     proj=hubs.item(hi).dataProjects.add('Adom'); break\n    except Exception as e: res['createErr']=str(e)[:60]\n except Exception as e: res['projErr2']=str(e)[:60]\nif not proj: res['errorCode']='no_cloud_project'\ntry:\n if proj is None: raise RuntimeError('no usable cloud project on this account')\n rf=proj.rootFolder\n wsf=_sub(_sub(rf,'Adom AI Workspace'),'Demo_Board')\n try:\n  doc.saveAs('LAN7800_3d', wsf, '3d package (footprint+chip)', '')\n except Exception as _se:\n  if 'CB_NAE' in str(_se) or 'same name' in str(_se):\n   import time as _t0; _nm='LAN7800_3d-'+_t0.strftime('%m%d%H%M%S')\n   doc.saveAs(_nm, wsf, '3d package (footprint+chip)', ''); res['renamedTo']=_nm\n  else: raise\n import time as _tt\n fid=None\n for w in range(40):\n  try: fid=doc.dataFile.id if doc.dataFile else None\n  except Exception: fid=None\n  if fid and 'dm.lineage:' in str(fid): break\n  adsk.doEvents(); _tt.sleep(1.5)\n res['path']=fid\n res['dims']=[round(dx*10,2),round(dy*10,2),round(dz*10,2)]\nexcept Exception as e: res['err']=str(e)[:80]\nresult=res\n"+ },+ {+  "modelPath": "C:/x/y z/chip.step",+  "orient": false,+  "pin1": null,+  "layersOff": [+   "Adom.SolderBalls",+   "Adom.Board"+  ],+  "task": "AI 3D packages",+  "name": "chip_3d",+  "script": "import adsk.core, adsk.fusion, math\napp=adsk.core.Application.get(); doc=app.activeDocument\nd=adsk.fusion.Design.cast(app.activeProduct); root=d.rootComponent\nim=app.importManager\nim.importToTarget(im.createSTEPImportOptions('C:/x/y z/chip.step'), root)\noc=root.occurrences.item(root.occurrences.count-1); bb=oc.boundingBox\ndx=bb.maxPoint.x-bb.minPoint.x; dy=bb.maxPoint.y-bb.minPoint.y; dz=bb.maxPoint.z-bb.minPoint.z\nPIN1=None\nres_pin1={'pad1_mm': None, 'mark_mm': None, 'rotatedDeg': 0, 'status': 'unchecked'}\ndef _mark(occ):\n    bb2=occ.boundingBox; zmax=bb2.maxPoint.z; best=None\n    def _w(comp, depth):\n        nonlocal best\n        if depth>6: return\n        for i in range(comp.bRepBodies.count):\n            b=comp.bRepBodies.item(i)\n            try: vol=b.volume\n            except Exception: vol=0\n            if vol*1000 < 5: continue\n            for e in b.edges:\n                try:\n                    g=e.geometry\n                    if g.objectType not in (adsk.core.Circle3D.classType(), adsk.core.Arc3D.classType()): continue\n                    c=g.center\n                    if abs(c.z-zmax)>0.03 or g.radius>0.1: continue\n                    score=abs(c.x)+abs(c.y)\n                    if best is None or score>best[0]: best=(score,c.x,c.y)\n                except Exception: pass\n        for j in range(comp.occurrences.count): _w(comp.occurrences.item(j).component, depth+1)\n    _w(occ.component, 0)\n    return None if best is None else (best[1],best[2])\ntry:\n    mk=_mark(oc)\n    if mk: res_pin1['mark_mm']=[round(mk[0]*10,2), round(mk[1]*10,2)]\n    if mk and PIN1:\n        import math as _m\n        want=_m.atan2(PIN1[1],PIN1[0]); have=_m.atan2(mk[1],mk[0])\n        k=int(round(((want-have)/(_m.pi/2)))) % 4\n        if k:\n            mat=oc.transform2.copy(); r=adsk.core.Matrix3D.create()\n            r.setToRotation(k*_m.pi/2, adsk.core.Vector3D.create(0,0,1), adsk.core.Point3D.create(0,0,0))\n            mat.transformBy(r); oc.transform2=mat\n            res_pin1['rotatedDeg']=k*90\n        res_pin1['status']='rotated' if k else 'aligned'\n    elif PIN1: res_pin1['status']='no_mark_on_chip'\n    else: res_pin1['status']='no_pad1_in_lbr'\nexcept Exception as _e: res_pin1['status']='error: '+str(_e)[:80]\ntry:\n app.activeViewport.fit()\nexcept: pass\ndef _sub(p,nm):\n import time as _ts\n for _try in range(4):\n  for i in range(p.dataFolders.count):\n   if str(p.dataFolders.item(i).name).lower()==str(nm).lower(): return p.dataFolders.item(i)\n  try: return p.dataFolders.add(nm)\n  except Exception as _fe:\n   if 'CB_NAE' not in str(_fe) and 'same name' not in str(_fe): raise\n   adsk.doEvents(); _ts.sleep(2.0)\n raise RuntimeError('cloud folder %s exists but cannot be resolved' % nm)\nres={}\nnames=[]; hidden=[]\ndef _layer(n):\n    n=(n or '').split(':')[0]\n    return n.startswith('Adom.') and n in LAYERS_OFF\ndef _walk(comp, group, hide):\n    for i in range(comp.bRepBodies.count):\n        b=comp.bRepBodies.item(i); names.append((group or '')+'/'+b.name)\n        if hide or _layer(b.name):\n            try:\n                b.isLightBulbOn=False; hidden.append((group or '')+'/'+b.name)\n            except Exception: pass\n    for j in range(comp.occurrences.count):\n        o=comp.occurrences.item(j); on=(o.component.name or o.name).split(':')[0]\n        g=group or (on if on.startswith('Adom.') else '')\n        h=hide or _layer(on)\n        if h and not hide:\n            try: o.isLightBulbOn=False\n            except Exception: pass\n        _walk(o.component, g, h)\nLAYERS_OFF=set(['Adom.Board', 'Adom.SolderBalls'])\ntry:\n    _walk(oc.component, '', False)\nexcept Exception as _e:\n    res['layersError']=str(_e)[:120]\nres['bodies']=names; res['layersHidden']=hidden\nres['pin1']=res_pin1\nproj=None\ntry: proj=app.data.activeProject\nexcept Exception as e: res['projErr']=str(e)[:60]\nif not proj:\n try:\n  hubs=app.data.dataHubs\n  for hi in range(hubs.count):\n   ps=hubs.item(hi).dataProjects\n   for pj2 in range(ps.count):\n    p2=ps.item(pj2)\n    ok=False\n    try: ok=(p2.id=='a.YnVzaW5lc3M6YWRvbTMjMjAyMzExMjk3MDM5NjAzMzE')\n    except Exception: ok=False\n    if not ok:\n     try: ok=(p2.name=='Main')\n     except Exception: continue\n    if ok: proj=p2; break\n   if proj: break\n except Exception as e: res['projErr']=str(e)[:60]\nif not proj:\n try:\n  hubs=app.data.dataHubs\n  for hi in range(hubs.count):\n   ps=hubs.item(hi).dataProjects\n   for pj2 in range(ps.count):\n    try:\n     p2=ps.item(pj2); p2.rootFolder\n     proj=p2; break\n    except Exception: continue\n   if proj: break\n  if not proj:\n   for hi in range(hubs.count):\n    try:\n     proj=hubs.item(hi).dataProjects.add('Adom'); break\n    except Exception as e: res['createErr']=str(e)[:60]\n except Exception as e: res['projErr2']=str(e)[:60]\nif not proj: res['errorCode']='no_cloud_project'\ntry:\n if proj is None: raise RuntimeError('no usable cloud project on this account')\n rf=proj.rootFolder\n wsf=_sub(_sub(rf,'Adom AI Workspace'),'AI 3D packages')\n try:\n  doc.saveAs('chip_3d', wsf, '3d package (footprint+chip)', '')\n except Exception as _se:\n  if 'CB_NAE' in str(_se) or 'same name' in str(_se):\n   import time as _t0; _nm='chip_3d-'+_t0.strftime('%m%d%H%M%S')\n   doc.saveAs(_nm, wsf, '3d package (footprint+chip)', ''); res['renamedTo']=_nm\n  else: raise\n import time as _tt\n fid=None\n for w in range(40):\n  try: fid=doc.dataFile.id if doc.dataFile else None\n  except Exception: fid=None\n  if fid and 'dm.lineage:' in str(fid): break\n  adsk.doEvents(); _tt.sleep(1.5)\n res['path']=fid\n res['dims']=[round(dx*10,2),round(dy*10,2),round(dz*10,2)]\nexcept Exception as e: res['err']=str(e)[:80]\nresult=res\n"+ }+]\ No newline at end of file
rust/bridge/tests/golden/mtp.jsonadded+39
@@ -0,0 +1,39 @@+{+ "libName": "Demo_Board",+ "fixture": "../../../lbr/tests/golden/Demo_Board.bound5.lbrx",+ "resistor": "../../../../resources/samples/0603WAF3300T5E.lbr",+ "cases": [+  {+   "deviceset": "LAN7800",+   "solo": true,+   "urn": "urn:adsk.wipprod:fs.file:vf.GOLD0?version=1",+   "rUrn": "",+   "sch": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE eagle SYSTEM \"eagle.dtd\">\n<eagle version=\"9.6.2\">\n<drawing>\n<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=\"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><schematic xreflabel=\"%F%N/%S.%C%R\" xrefpart=\"/%S.%C%R\"><libraries><library name=\"Demo_Board\"><packages><package name=\"QFN-48_7x7mm\">\n  <description>QFN-48, 7 x 7 mm</description>\n  <smd name=\"1\" x=\"-3.5000\" y=\"2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"2\" x=\"-3.5000\" y=\"2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"3\" x=\"-3.5000\" y=\"1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"4\" x=\"-3.5000\" y=\"1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"5\" x=\"-3.5000\" y=\"0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"6\" x=\"-3.5000\" y=\"0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"7\" x=\"-3.5000\" y=\"-0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"8\" x=\"-3.5000\" y=\"-0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"9\" x=\"-3.5000\" y=\"-1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"10\" x=\"-3.5000\" y=\"-1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"11\" x=\"-3.5000\" y=\"-2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"12\" x=\"-3.5000\" y=\"-2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"13\" x=\"-2.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"14\" x=\"-2.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"15\" x=\"-1.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"16\" x=\"-1.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"17\" x=\"-0.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"18\" x=\"-0.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"19\" x=\"0.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"20\" x=\"0.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"21\" x=\"1.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"22\" x=\"1.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"23\" x=\"2.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"24\" x=\"2.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"25\" x=\"3.5000\" y=\"-2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"26\" x=\"3.5000\" y=\"-2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"27\" x=\"3.5000\" y=\"-1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"28\" x=\"3.5000\" y=\"-1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"29\" x=\"3.5000\" y=\"-0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"30\" x=\"3.5000\" y=\"-0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"31\" x=\"3.5000\" y=\"0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"32\" x=\"3.5000\" y=\"0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"33\" x=\"3.5000\" y=\"1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"34\" x=\"3.5000\" y=\"1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"35\" x=\"3.5000\" y=\"2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"36\" x=\"3.5000\" y=\"2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"37\" x=\"2.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"38\" x=\"2.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"39\" x=\"1.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"40\" x=\"1.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"41\" x=\"0.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"42\" x=\"0.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"43\" x=\"-0.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"44\" x=\"-0.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"45\" x=\"-1.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"46\" x=\"-1.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"47\" x=\"-2.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"48\" x=\"-2.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"49\" x=\"0.0000\" y=\"-0.0000\" dx=\"5.3000\" dy=\"5.3000\" layer=\"1\"/>\n  <circle x=\"-3.5000\" y=\"3.5000\" radius=\"0.0300\" width=\"0.0600\" layer=\"21\"/>\n  <polygon width=\"0.1000\" layer=\"51\">\n    <vertex x=\"-2.5000\" y=\"3.5000\"/>\n    <vertex x=\"3.5000\" y=\"3.5000\"/>\n    <vertex x=\"3.5000\" y=\"-3.5000\"/>\n    <vertex x=\"-3.5000\" y=\"-3.5000\"/>\n    <vertex x=\"-3.5000\" y=\"2.5000\"/>\n  </polygon>\n  <wire x1=\"3.7200\" y1=\"3.7200\" x2=\"3.7200\" y2=\"3.2800\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"3.2800\" y1=\"3.7200\" x2=\"3.7200\" y2=\"3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"3.7200\" x2=\"-3.2800\" y2=\"3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"3.2800\" x2=\"-3.7200\" y2=\"3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"-3.2800\" x2=\"-3.7200\" y2=\"-3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"3.7200\" y1=\"-3.7200\" x2=\"3.7200\" y2=\"-3.2800\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"3.2800\" y1=\"-3.7200\" x2=\"3.7200\" y2=\"-3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"-3.7200\" x2=\"-3.2800\" y2=\"-3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-4.1000\" y1=\"3.5200\" x2=\"-4.1200\" y2=\"3.4452\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1200\" y1=\"3.4452\" x2=\"-4.1747\" y2=\"3.3903\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1747\" y1=\"3.3903\" x2=\"-4.2494\" y2=\"3.3700\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.2494\" y1=\"3.3700\" x2=\"-4.3243\" y2=\"3.3897\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3243\" y1=\"3.3897\" x2=\"-4.3794\" y2=\"3.4441\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3794\" y1=\"3.4441\" x2=\"-4.4000\" y2=\"3.5188\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.4000\" y1=\"3.5188\" x2=\"-4.3806\" y2=\"3.5938\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3806\" y1=\"3.5938\" x2=\"-4.3264\" y2=\"3.6491\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3264\" y1=\"3.6491\" x2=\"-4.2519\" y2=\"3.6700\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.2519\" y1=\"3.6700\" x2=\"-4.1768\" y2=\"3.6510\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1768\" y1=\"3.6510\" x2=\"-4.1213\" y2=\"3.5970\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1213\" y1=\"3.5970\" x2=\"-4.1000\" y2=\"3.5225\" width=\"0.3000\" layer=\"21\"/>\n  <text x=\"0\" y=\"4.600\" size=\"1.27\" layer=\"25\" align=\"bottom-center\">&gt;NAME</text>\n  <text x=\"0\" y=\"-4.600\" size=\"1.27\" layer=\"27\" align=\"top-center\">&gt;VALUE</text>\n</package></packages><packages3d><package3d name=\"LAN7800\" urn=\"\" wip_urn=\"urn:adsk.wipprod:fs.file:vf.GOLD0?version=1\" locally_modified=\"yes\" type=\"model\"><packageinstances><packageinstance name=\"QFN-48_7x7mm\"/></packageinstances></package3d></packages3d><symbols><symbol name=\"LAN7800\">\n  <description>Microchip LAN7800 SuperSpeed USB 3.1 Gen1 to 10/100/1000 Ethernet Controller, QFN-48</description>\n  <wire x1=\"-34.29\" y1=\"33.02\" x2=\"34.29\" y2=\"33.02\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"34.29\" y1=\"33.02\" x2=\"34.29\" y2=\"-33.02\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"34.29\" y1=\"-33.02\" x2=\"-34.29\" y2=\"-33.02\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"-34.29\" y1=\"-33.02\" x2=\"-34.29\" y2=\"33.02\" width=\"0.254\" layer=\"94\"/>\n  <circle x=\"-33.0200\" y=\"31.7500\" radius=\"0.3800\" width=\"0.1524\" layer=\"94\"/>\n  <text x=\"0.0000\" y=\"35.5600\" size=\"1.27\" layer=\"95\" align=\"center\">&gt;NAME</text>\n  <text x=\"0.0000\" y=\"-35.5600\" size=\"1.27\" layer=\"96\" align=\"center\">&gt;VALUE</text>\n  <pin name=\"TR0P\" x=\"-36.83\" y=\"27.94\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR0N\" x=\"-36.83\" y=\"25.4\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD25A\" x=\"-36.83\" y=\"22.86\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR1P\" x=\"-36.83\" y=\"20.32\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR1N\" x=\"-36.83\" y=\"17.78\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD25A@2\" x=\"-36.83\" y=\"15.24\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR2P\" x=\"-36.83\" y=\"12.7\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR2N\" x=\"-36.83\" y=\"10.16\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD25A@3\" x=\"-36.83\" y=\"7.62\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR3P\" x=\"-36.83\" y=\"5.08\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR3N\" x=\"-36.83\" y=\"2.54\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD25A@4\" x=\"-36.83\" y=\"0\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD12_SW_OUT\" x=\"-36.83\" y=\"-2.54\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD_SW_IN\" x=\"-36.83\" y=\"-5.08\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD12_SW_FB\" x=\"-36.83\" y=\"-7.62\" length=\"short\" direction=\"io\"/>\n  <pin name=\"EECS/GPIO0\" x=\"-36.83\" y=\"-10.16\" length=\"short\" direction=\"io\"/>\n  <pin name=\"EEDI/GPIO1\" x=\"-36.83\" y=\"-12.7\" length=\"short\" direction=\"io\"/>\n  <pin name=\"EEDO/LED0/GPIO2\" x=\"-36.83\" y=\"-15.24\" length=\"short\" direction=\"io\"/>\n  <pin name=\"EECLK/LED1/GPIO3\" x=\"-36.83\" y=\"-17.78\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDDVARIO\" x=\"-36.83\" y=\"-20.32\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD12CORE\" x=\"-36.83\" y=\"-22.86\" length=\"short\" direction=\"io\"/>\n  <pin name=\"PME_N/GPIO4\" x=\"-36.83\" y=\"-25.4\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VBUS_DET\" x=\"-36.83\" y=\"-27.94\" length=\"short\" direction=\"io\"/>\n  <pin name=\"SUSPEND_N/LED2/GPIO5\" x=\"-36.83\" y=\"-30.48\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VSS\" x=\"36.83\" y=\"30.48\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"REF_FILT\" x=\"36.83\" y=\"27.94\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"REF_REXT\" x=\"36.83\" y=\"25.4\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD33_REG_IN\" x=\"36.83\" y=\"22.86\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD25_REG_OUT\" x=\"36.83\" y=\"20.32\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD12A\" x=\"36.83\" y=\"17.78\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"PME_MODE/GPIO7\" x=\"36.83\" y=\"15.24\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD12CORE@2\" x=\"36.83\" y=\"12.7\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"XO\" x=\"36.83\" y=\"10.16\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"XI\" x=\"36.83\" y=\"7.62\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDDVARIO@2\" x=\"36.83\" y=\"5.08\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD33A\" x=\"36.83\" y=\"2.54\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USBRBIAS\" x=\"36.83\" y=\"0\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDDVARIO@3\" x=\"36.83\" y=\"-2.54\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"RESET_N/PME_CLEAR\" x=\"36.83\" y=\"-5.08\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"TEST\" x=\"36.83\" y=\"-7.62\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"LED3/GPIO6\" x=\"36.83\" y=\"-10.16\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USB3_RXDM\" x=\"36.83\" y=\"-12.7\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USB3_RXDP\" x=\"36.83\" y=\"-15.24\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD12A@2\" x=\"36.83\" y=\"-17.78\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USB3_TXDM\" x=\"36.83\" y=\"-20.32\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USB3_TXDP\" x=\"36.83\" y=\"-22.86\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USB2_DM\" x=\"36.83\" y=\"-25.4\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USB2_DP\" x=\"36.83\" y=\"-27.94\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD12A@3\" x=\"36.83\" y=\"-30.48\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n</symbol></symbols><devicesets><deviceset name=\"LAN7800\" prefix=\"U\">\n  <description>Microchip LAN7800 SuperSpeed USB 3.1 Gen1 to 10/100/1000 Ethernet Controller, QFN-48</description>\n  <gates>\n    <gate name=\"G$1\" symbol=\"LAN7800\" x=\"0\" y=\"0\"/>\n  </gates>\n  <devices>\n    <device name=\"\" package=\"QFN-48_7x7mm\">\n      <connects>\n        <connect gate=\"G$1\" pin=\"TR0P\" pad=\"1\"/>\n        <connect gate=\"G$1\" pin=\"TR0N\" pad=\"2\"/>\n        <connect gate=\"G$1\" pin=\"VDD25A\" pad=\"3\"/>\n        <connect gate=\"G$1\" pin=\"TR1P\" pad=\"4\"/>\n        <connect gate=\"G$1\" pin=\"TR1N\" pad=\"5\"/>\n        <connect gate=\"G$1\" pin=\"VDD25A@2\" pad=\"6\"/>\n        <connect gate=\"G$1\" pin=\"TR2P\" pad=\"7\"/>\n        <connect gate=\"G$1\" pin=\"TR2N\" pad=\"8\"/>\n        <connect gate=\"G$1\" pin=\"VDD25A@3\" pad=\"9\"/>\n        <connect gate=\"G$1\" pin=\"TR3P\" pad=\"10\"/>\n        <connect gate=\"G$1\" pin=\"TR3N\" pad=\"11\"/>\n        <connect gate=\"G$1\" pin=\"VDD25A@4\" pad=\"12\"/>\n        <connect gate=\"G$1\" pin=\"VDD12_SW_OUT\" pad=\"13\"/>\n        <connect gate=\"G$1\" pin=\"VDD_SW_IN\" pad=\"14\"/>\n        <connect gate=\"G$1\" pin=\"VDD12_SW_FB\" pad=\"15\"/>\n        <connect gate=\"G$1\" pin=\"EECS/GPIO0\" pad=\"16\"/>\n        <connect gate=\"G$1\" pin=\"EEDI/GPIO1\" pad=\"17\"/>\n        <connect gate=\"G$1\" pin=\"EEDO/LED0/GPIO2\" pad=\"18\"/>\n        <connect gate=\"G$1\" pin=\"EECLK/LED1/GPIO3\" pad=\"19\"/>\n        <connect gate=\"G$1\" pin=\"VDDVARIO\" pad=\"20\"/>\n        <connect gate=\"G$1\" pin=\"VDD12CORE\" pad=\"21\"/>\n        <connect gate=\"G$1\" pin=\"PME_N/GPIO4\" pad=\"22\"/>\n        <connect gate=\"G$1\" pin=\"VBUS_DET\" pad=\"23\"/>\n        <connect gate=\"G$1\" pin=\"SUSPEND_N/LED2/GPIO5\" pad=\"24\"/>\n        <connect gate=\"G$1\" pin=\"VSS\" pad=\"49\"/>\n        <connect gate=\"G$1\" pin=\"REF_FILT\" pad=\"48\"/>\n        <connect gate=\"G$1\" pin=\"REF_REXT\" pad=\"47\"/>\n        <connect gate=\"G$1\" pin=\"VDD33_REG_IN\" pad=\"46\"/>\n        <connect gate=\"G$1\" pin=\"VDD25_REG_OUT\" pad=\"45\"/>\n        <connect gate=\"G$1\" pin=\"VDD12A\" pad=\"44\"/>\n        <connect gate=\"G$1\" pin=\"PME_MODE/GPIO7\" pad=\"43\"/>\n        <connect gate=\"G$1\" pin=\"VDD12CORE@2\" pad=\"42\"/>\n        <connect gate=\"G$1\" pin=\"XO\" pad=\"41\"/>\n        <connect gate=\"G$1\" pin=\"XI\" pad=\"40\"/>\n        <connect gate=\"G$1\" pin=\"VDDVARIO@2\" pad=\"39\"/>\n        <connect gate=\"G$1\" pin=\"VDD33A\" pad=\"38\"/>\n        <connect gate=\"G$1\" pin=\"USBRBIAS\" pad=\"37\"/>\n        <connect gate=\"G$1\" pin=\"VDDVARIO@3\" pad=\"36\"/>\n        <connect gate=\"G$1\" pin=\"RESET_N/PME_CLEAR\" pad=\"35\"/>\n        <connect gate=\"G$1\" pin=\"TEST\" pad=\"34\"/>\n        <connect gate=\"G$1\" pin=\"LED3/GPIO6\" pad=\"33\"/>\n        <connect gate=\"G$1\" pin=\"USB3_RXDM\" pad=\"32\"/>\n        <connect gate=\"G$1\" pin=\"USB3_RXDP\" pad=\"31\"/>\n        <connect gate=\"G$1\" pin=\"VDD12A@2\" pad=\"30\"/>\n        <connect gate=\"G$1\" pin=\"USB3_TXDM\" pad=\"29\"/>\n        <connect gate=\"G$1\" pin=\"USB3_TXDP\" pad=\"28\"/>\n        <connect gate=\"G$1\" pin=\"USB2_DM\" pad=\"27\"/>\n        <connect gate=\"G$1\" pin=\"USB2_DP\" pad=\"26\"/>\n        <connect gate=\"G$1\" pin=\"VDD12A@3\" pad=\"25\"/>\n      </connects>\n\n      <technologies><technology name=\"\"/></technologies>\n    </device>\n  </devices>\n</deviceset></devicesets></library></libraries><attributes/><variantdefs/><classes><class number=\"0\" name=\"default\" width=\"0\" drill=\"0\"/></classes><parts><part name=\"U1\" library=\"Demo_Board\" deviceset=\"LAN7800\" device=\"\"/></parts><sheets><sheet><plain><text x=\"0\" y=\"25.4\" size=\"2.54\" layer=\"97\">LAN7800 - Adom component demo</text></plain><instances><instance part=\"U1\" gate=\"G$1\" x=\"25.4\" y=\"12.7\"/></instances><busses/><nets/></sheet></sheets></schematic></drawing></eagle>\n",+   "brd": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE eagle SYSTEM \"eagle.dtd\">\n<eagle version=\"9.6.2\">\n<drawing>\n<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>\n<layer number=\"1\" name=\"Top\" color=\"4\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"16\" name=\"Bottom\" color=\"1\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"17\" name=\"Pads\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"18\" name=\"Vias\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"19\" name=\"Unrouted\" color=\"6\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"20\" name=\"Dimension\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"21\" name=\"tPlace\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"22\" name=\"bPlace\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"23\" name=\"tOrigins\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"24\" name=\"bOrigins\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"25\" name=\"tNames\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"26\" name=\"bNames\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"27\" name=\"tValues\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"28\" name=\"bValues\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"29\" name=\"tStop\" color=\"7\" fill=\"3\" visible=\"no\" active=\"yes\"/>\n<layer number=\"30\" name=\"bStop\" color=\"7\" fill=\"6\" visible=\"no\" active=\"yes\"/>\n<layer number=\"31\" name=\"tCream\" color=\"7\" fill=\"4\" visible=\"no\" active=\"yes\"/>\n<layer number=\"32\" name=\"bCream\" color=\"7\" fill=\"5\" visible=\"no\" active=\"yes\"/>\n<layer number=\"33\" name=\"tFinish\" color=\"6\" fill=\"3\" visible=\"no\" active=\"yes\"/>\n<layer number=\"34\" name=\"bFinish\" color=\"6\" fill=\"6\" visible=\"no\" active=\"yes\"/>\n<layer number=\"35\" name=\"tGlue\" color=\"7\" fill=\"4\" visible=\"no\" active=\"yes\"/>\n<layer number=\"36\" name=\"bGlue\" color=\"7\" fill=\"5\" visible=\"no\" active=\"yes\"/>\n<layer number=\"37\" name=\"tTest\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"38\" name=\"bTest\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"39\" name=\"tKeepout\" color=\"4\" fill=\"11\" visible=\"no\" active=\"yes\"/>\n<layer number=\"40\" name=\"bKeepout\" color=\"1\" fill=\"11\" visible=\"no\" active=\"yes\"/>\n<layer number=\"41\" name=\"tRestrict\" color=\"4\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"42\" name=\"bRestrict\" color=\"1\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"43\" name=\"vRestrict\" color=\"2\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"44\" name=\"Drills\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"45\" name=\"Holes\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"46\" name=\"Milling\" color=\"3\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"47\" name=\"Measures\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"48\" name=\"Document\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"49\" name=\"Reference\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"91\" name=\"Nets\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"92\" name=\"Busses\" color=\"1\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"93\" name=\"Pins\" color=\"2\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"94\" name=\"Symbols\" color=\"4\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"95\" name=\"Names\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"96\" name=\"Values\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"97\" name=\"Info\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"98\" name=\"Guide\" color=\"6\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n</layers><board><plain><wire x1=\"0\" y1=\"0\" x2=\"14.7\" y2=\"0\" width=\"0.2\" layer=\"20\"/><wire x1=\"14.7\" y1=\"0\" x2=\"14.7\" y2=\"14.0\" width=\"0.2\" layer=\"20\"/><wire x1=\"14.7\" y1=\"14.0\" x2=\"0\" y2=\"14.0\" width=\"0.2\" layer=\"20\"/><wire x1=\"0\" y1=\"14.0\" x2=\"0\" y2=\"0\" width=\"0.2\" layer=\"20\"/></plain><libraries><library name=\"Demo_Board\"><packages><package name=\"QFN-48_7x7mm\">\n  <description>QFN-48, 7 x 7 mm</description>\n  <smd name=\"1\" x=\"-3.5000\" y=\"2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"2\" x=\"-3.5000\" y=\"2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"3\" x=\"-3.5000\" y=\"1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"4\" x=\"-3.5000\" y=\"1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"5\" x=\"-3.5000\" y=\"0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"6\" x=\"-3.5000\" y=\"0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"7\" x=\"-3.5000\" y=\"-0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"8\" x=\"-3.5000\" y=\"-0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"9\" x=\"-3.5000\" y=\"-1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"10\" x=\"-3.5000\" y=\"-1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"11\" x=\"-3.5000\" y=\"-2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"12\" x=\"-3.5000\" y=\"-2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"13\" x=\"-2.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"14\" x=\"-2.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"15\" x=\"-1.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"16\" x=\"-1.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"17\" x=\"-0.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"18\" x=\"-0.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"19\" x=\"0.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"20\" x=\"0.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"21\" x=\"1.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"22\" x=\"1.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"23\" x=\"2.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"24\" x=\"2.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"25\" x=\"3.5000\" y=\"-2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"26\" x=\"3.5000\" y=\"-2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"27\" x=\"3.5000\" y=\"-1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"28\" x=\"3.5000\" y=\"-1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"29\" x=\"3.5000\" y=\"-0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"30\" x=\"3.5000\" y=\"-0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"31\" x=\"3.5000\" y=\"0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"32\" x=\"3.5000\" y=\"0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"33\" x=\"3.5000\" y=\"1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"34\" x=\"3.5000\" y=\"1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"35\" x=\"3.5000\" y=\"2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"36\" x=\"3.5000\" y=\"2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"37\" x=\"2.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"38\" x=\"2.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"39\" x=\"1.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"40\" x=\"1.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"41\" x=\"0.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"42\" x=\"0.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"43\" x=\"-0.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"44\" x=\"-0.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"45\" x=\"-1.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"46\" x=\"-1.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"47\" x=\"-2.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"48\" x=\"-2.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"49\" x=\"0.0000\" y=\"-0.0000\" dx=\"5.3000\" dy=\"5.3000\" layer=\"1\"/>\n  <circle x=\"-3.5000\" y=\"3.5000\" radius=\"0.0300\" width=\"0.0600\" layer=\"21\"/>\n  <polygon width=\"0.1000\" layer=\"51\">\n    <vertex x=\"-2.5000\" y=\"3.5000\"/>\n    <vertex x=\"3.5000\" y=\"3.5000\"/>\n    <vertex x=\"3.5000\" y=\"-3.5000\"/>\n    <vertex x=\"-3.5000\" y=\"-3.5000\"/>\n    <vertex x=\"-3.5000\" y=\"2.5000\"/>\n  </polygon>\n  <wire x1=\"3.7200\" y1=\"3.7200\" x2=\"3.7200\" y2=\"3.2800\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"3.2800\" y1=\"3.7200\" x2=\"3.7200\" y2=\"3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"3.7200\" x2=\"-3.2800\" y2=\"3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"3.2800\" x2=\"-3.7200\" y2=\"3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"-3.2800\" x2=\"-3.7200\" y2=\"-3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"3.7200\" y1=\"-3.7200\" x2=\"3.7200\" y2=\"-3.2800\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"3.2800\" y1=\"-3.7200\" x2=\"3.7200\" y2=\"-3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"-3.7200\" x2=\"-3.2800\" y2=\"-3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-4.1000\" y1=\"3.5200\" x2=\"-4.1200\" y2=\"3.4452\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1200\" y1=\"3.4452\" x2=\"-4.1747\" y2=\"3.3903\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1747\" y1=\"3.3903\" x2=\"-4.2494\" y2=\"3.3700\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.2494\" y1=\"3.3700\" x2=\"-4.3243\" y2=\"3.3897\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3243\" y1=\"3.3897\" x2=\"-4.3794\" y2=\"3.4441\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3794\" y1=\"3.4441\" x2=\"-4.4000\" y2=\"3.5188\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.4000\" y1=\"3.5188\" x2=\"-4.3806\" y2=\"3.5938\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3806\" y1=\"3.5938\" x2=\"-4.3264\" y2=\"3.6491\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3264\" y1=\"3.6491\" x2=\"-4.2519\" y2=\"3.6700\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.2519\" y1=\"3.6700\" x2=\"-4.1768\" y2=\"3.6510\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1768\" y1=\"3.6510\" x2=\"-4.1213\" y2=\"3.5970\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1213\" y1=\"3.5970\" x2=\"-4.1000\" y2=\"3.5225\" width=\"0.3000\" layer=\"21\"/>\n  <text x=\"0\" y=\"4.600\" size=\"1.27\" layer=\"25\" align=\"bottom-center\">&gt;NAME</text>\n  <text x=\"0\" y=\"-4.600\" size=\"1.27\" layer=\"27\" align=\"top-center\">&gt;VALUE</text>\n</package></packages><packages3d><package3d name=\"LAN7800\" urn=\"\" wip_urn=\"urn:adsk.wipprod:fs.file:vf.GOLD0?version=1\" locally_modified=\"yes\" type=\"model\"><packageinstances><packageinstance name=\"QFN-48_7x7mm\"/></packageinstances></package3d></packages3d></library></libraries><attributes/><variantdefs/><classes><class number=\"0\" name=\"default\" width=\"0\" drill=\"0\"/></classes><designrules name=\"default\"/><autorouter/><elements><element name=\"U1\" library=\"Demo_Board\" package=\"QFN-48_7x7mm\" value=\"\" x=\"7.7\" y=\"7.0\" package3d_urn=\"urn:adsk.wipprod:fs.file:vf.GOLD0?version=1\"/></elements><signals/></board></drawing></eagle>\n"+  },+  {+   "deviceset": "LAN7800",+   "solo": false,+   "urn": "urn:adsk.wipprod:fs.file:vf.GOLD0?version=1",+   "rUrn": "urn:adsk.wipprod:fs.file:vf.RRR?version=1",+   "sch": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE eagle SYSTEM \"eagle.dtd\">\n<eagle version=\"9.6.2\">\n<drawing>\n<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=\"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><schematic xreflabel=\"%F%N/%S.%C%R\" xrefpart=\"/%S.%C%R\"><libraries><library name=\"Demo_Board\"><packages><package name=\"QFN-48_7x7mm\">\n  <description>QFN-48, 7 x 7 mm</description>\n  <smd name=\"1\" x=\"-3.5000\" y=\"2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"2\" x=\"-3.5000\" y=\"2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"3\" x=\"-3.5000\" y=\"1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"4\" x=\"-3.5000\" y=\"1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"5\" x=\"-3.5000\" y=\"0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"6\" x=\"-3.5000\" y=\"0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"7\" x=\"-3.5000\" y=\"-0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"8\" x=\"-3.5000\" y=\"-0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"9\" x=\"-3.5000\" y=\"-1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"10\" x=\"-3.5000\" y=\"-1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"11\" x=\"-3.5000\" y=\"-2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"12\" x=\"-3.5000\" y=\"-2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"13\" x=\"-2.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"14\" x=\"-2.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"15\" x=\"-1.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"16\" x=\"-1.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"17\" x=\"-0.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"18\" x=\"-0.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"19\" x=\"0.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"20\" x=\"0.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"21\" x=\"1.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"22\" x=\"1.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"23\" x=\"2.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"24\" x=\"2.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"25\" x=\"3.5000\" y=\"-2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"26\" x=\"3.5000\" y=\"-2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"27\" x=\"3.5000\" y=\"-1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"28\" x=\"3.5000\" y=\"-1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"29\" x=\"3.5000\" y=\"-0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"30\" x=\"3.5000\" y=\"-0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"31\" x=\"3.5000\" y=\"0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"32\" x=\"3.5000\" y=\"0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"33\" x=\"3.5000\" y=\"1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"34\" x=\"3.5000\" y=\"1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"35\" x=\"3.5000\" y=\"2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"36\" x=\"3.5000\" y=\"2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"37\" x=\"2.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"38\" x=\"2.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"39\" x=\"1.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"40\" x=\"1.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"41\" x=\"0.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"42\" x=\"0.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"43\" x=\"-0.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"44\" x=\"-0.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"45\" x=\"-1.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"46\" x=\"-1.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"47\" x=\"-2.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"48\" x=\"-2.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"49\" x=\"0.0000\" y=\"-0.0000\" dx=\"5.3000\" dy=\"5.3000\" layer=\"1\"/>\n  <circle x=\"-3.5000\" y=\"3.5000\" radius=\"0.0300\" width=\"0.0600\" layer=\"21\"/>\n  <polygon width=\"0.1000\" layer=\"51\">\n    <vertex x=\"-2.5000\" y=\"3.5000\"/>\n    <vertex x=\"3.5000\" y=\"3.5000\"/>\n    <vertex x=\"3.5000\" y=\"-3.5000\"/>\n    <vertex x=\"-3.5000\" y=\"-3.5000\"/>\n    <vertex x=\"-3.5000\" y=\"2.5000\"/>\n  </polygon>\n  <wire x1=\"3.7200\" y1=\"3.7200\" x2=\"3.7200\" y2=\"3.2800\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"3.2800\" y1=\"3.7200\" x2=\"3.7200\" y2=\"3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"3.7200\" x2=\"-3.2800\" y2=\"3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"3.2800\" x2=\"-3.7200\" y2=\"3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"-3.2800\" x2=\"-3.7200\" y2=\"-3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"3.7200\" y1=\"-3.7200\" x2=\"3.7200\" y2=\"-3.2800\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"3.2800\" y1=\"-3.7200\" x2=\"3.7200\" y2=\"-3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"-3.7200\" x2=\"-3.2800\" y2=\"-3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-4.1000\" y1=\"3.5200\" x2=\"-4.1200\" y2=\"3.4452\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1200\" y1=\"3.4452\" x2=\"-4.1747\" y2=\"3.3903\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1747\" y1=\"3.3903\" x2=\"-4.2494\" y2=\"3.3700\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.2494\" y1=\"3.3700\" x2=\"-4.3243\" y2=\"3.3897\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3243\" y1=\"3.3897\" x2=\"-4.3794\" y2=\"3.4441\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3794\" y1=\"3.4441\" x2=\"-4.4000\" y2=\"3.5188\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.4000\" y1=\"3.5188\" x2=\"-4.3806\" y2=\"3.5938\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3806\" y1=\"3.5938\" x2=\"-4.3264\" y2=\"3.6491\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3264\" y1=\"3.6491\" x2=\"-4.2519\" y2=\"3.6700\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.2519\" y1=\"3.6700\" x2=\"-4.1768\" y2=\"3.6510\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1768\" y1=\"3.6510\" x2=\"-4.1213\" y2=\"3.5970\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1213\" y1=\"3.5970\" x2=\"-4.1000\" y2=\"3.5225\" width=\"0.3000\" layer=\"21\"/>\n  <text x=\"0\" y=\"4.600\" size=\"1.27\" layer=\"25\" align=\"bottom-center\">&gt;NAME</text>\n  <text x=\"0\" y=\"-4.600\" size=\"1.27\" layer=\"27\" align=\"top-center\">&gt;VALUE</text>\n</package></packages><packages3d><package3d name=\"LAN7800\" urn=\"\" wip_urn=\"urn:adsk.wipprod:fs.file:vf.GOLD0?version=1\" locally_modified=\"yes\" type=\"model\"><packageinstances><packageinstance name=\"QFN-48_7x7mm\"/></packageinstances></package3d></packages3d><symbols><symbol name=\"LAN7800\">\n  <description>Microchip LAN7800 SuperSpeed USB 3.1 Gen1 to 10/100/1000 Ethernet Controller, QFN-48</description>\n  <wire x1=\"-34.29\" y1=\"33.02\" x2=\"34.29\" y2=\"33.02\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"34.29\" y1=\"33.02\" x2=\"34.29\" y2=\"-33.02\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"34.29\" y1=\"-33.02\" x2=\"-34.29\" y2=\"-33.02\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"-34.29\" y1=\"-33.02\" x2=\"-34.29\" y2=\"33.02\" width=\"0.254\" layer=\"94\"/>\n  <circle x=\"-33.0200\" y=\"31.7500\" radius=\"0.3800\" width=\"0.1524\" layer=\"94\"/>\n  <text x=\"0.0000\" y=\"35.5600\" size=\"1.27\" layer=\"95\" align=\"center\">&gt;NAME</text>\n  <text x=\"0.0000\" y=\"-35.5600\" size=\"1.27\" layer=\"96\" align=\"center\">&gt;VALUE</text>\n  <pin name=\"TR0P\" x=\"-36.83\" y=\"27.94\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR0N\" x=\"-36.83\" y=\"25.4\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD25A\" x=\"-36.83\" y=\"22.86\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR1P\" x=\"-36.83\" y=\"20.32\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR1N\" x=\"-36.83\" y=\"17.78\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD25A@2\" x=\"-36.83\" y=\"15.24\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR2P\" x=\"-36.83\" y=\"12.7\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR2N\" x=\"-36.83\" y=\"10.16\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD25A@3\" x=\"-36.83\" y=\"7.62\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR3P\" x=\"-36.83\" y=\"5.08\" length=\"short\" direction=\"io\"/>\n  <pin name=\"TR3N\" x=\"-36.83\" y=\"2.54\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD25A@4\" x=\"-36.83\" y=\"0\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD12_SW_OUT\" x=\"-36.83\" y=\"-2.54\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD_SW_IN\" x=\"-36.83\" y=\"-5.08\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD12_SW_FB\" x=\"-36.83\" y=\"-7.62\" length=\"short\" direction=\"io\"/>\n  <pin name=\"EECS/GPIO0\" x=\"-36.83\" y=\"-10.16\" length=\"short\" direction=\"io\"/>\n  <pin name=\"EEDI/GPIO1\" x=\"-36.83\" y=\"-12.7\" length=\"short\" direction=\"io\"/>\n  <pin name=\"EEDO/LED0/GPIO2\" x=\"-36.83\" y=\"-15.24\" length=\"short\" direction=\"io\"/>\n  <pin name=\"EECLK/LED1/GPIO3\" x=\"-36.83\" y=\"-17.78\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDDVARIO\" x=\"-36.83\" y=\"-20.32\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VDD12CORE\" x=\"-36.83\" y=\"-22.86\" length=\"short\" direction=\"io\"/>\n  <pin name=\"PME_N/GPIO4\" x=\"-36.83\" y=\"-25.4\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VBUS_DET\" x=\"-36.83\" y=\"-27.94\" length=\"short\" direction=\"io\"/>\n  <pin name=\"SUSPEND_N/LED2/GPIO5\" x=\"-36.83\" y=\"-30.48\" length=\"short\" direction=\"io\"/>\n  <pin name=\"VSS\" x=\"36.83\" y=\"30.48\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"REF_FILT\" x=\"36.83\" y=\"27.94\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"REF_REXT\" x=\"36.83\" y=\"25.4\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD33_REG_IN\" x=\"36.83\" y=\"22.86\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD25_REG_OUT\" x=\"36.83\" y=\"20.32\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD12A\" x=\"36.83\" y=\"17.78\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"PME_MODE/GPIO7\" x=\"36.83\" y=\"15.24\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD12CORE@2\" x=\"36.83\" y=\"12.7\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"XO\" x=\"36.83\" y=\"10.16\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"XI\" x=\"36.83\" y=\"7.62\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDDVARIO@2\" x=\"36.83\" y=\"5.08\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD33A\" x=\"36.83\" y=\"2.54\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USBRBIAS\" x=\"36.83\" y=\"0\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDDVARIO@3\" x=\"36.83\" y=\"-2.54\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"RESET_N/PME_CLEAR\" x=\"36.83\" y=\"-5.08\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"TEST\" x=\"36.83\" y=\"-7.62\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"LED3/GPIO6\" x=\"36.83\" y=\"-10.16\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USB3_RXDM\" x=\"36.83\" y=\"-12.7\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USB3_RXDP\" x=\"36.83\" y=\"-15.24\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD12A@2\" x=\"36.83\" y=\"-17.78\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USB3_TXDM\" x=\"36.83\" y=\"-20.32\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USB3_TXDP\" x=\"36.83\" y=\"-22.86\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USB2_DM\" x=\"36.83\" y=\"-25.4\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"USB2_DP\" x=\"36.83\" y=\"-27.94\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"VDD12A@3\" x=\"36.83\" y=\"-30.48\" length=\"short\" direction=\"io\" rot=\"R180\"/>\n</symbol></symbols><devicesets><deviceset name=\"LAN7800\" prefix=\"U\">\n  <description>Microchip LAN7800 SuperSpeed USB 3.1 Gen1 to 10/100/1000 Ethernet Controller, QFN-48</description>\n  <gates>\n    <gate name=\"G$1\" symbol=\"LAN7800\" x=\"0\" y=\"0\"/>\n  </gates>\n  <devices>\n    <device name=\"\" package=\"QFN-48_7x7mm\">\n      <connects>\n        <connect gate=\"G$1\" pin=\"TR0P\" pad=\"1\"/>\n        <connect gate=\"G$1\" pin=\"TR0N\" pad=\"2\"/>\n        <connect gate=\"G$1\" pin=\"VDD25A\" pad=\"3\"/>\n        <connect gate=\"G$1\" pin=\"TR1P\" pad=\"4\"/>\n        <connect gate=\"G$1\" pin=\"TR1N\" pad=\"5\"/>\n        <connect gate=\"G$1\" pin=\"VDD25A@2\" pad=\"6\"/>\n        <connect gate=\"G$1\" pin=\"TR2P\" pad=\"7\"/>\n        <connect gate=\"G$1\" pin=\"TR2N\" pad=\"8\"/>\n        <connect gate=\"G$1\" pin=\"VDD25A@3\" pad=\"9\"/>\n        <connect gate=\"G$1\" pin=\"TR3P\" pad=\"10\"/>\n        <connect gate=\"G$1\" pin=\"TR3N\" pad=\"11\"/>\n        <connect gate=\"G$1\" pin=\"VDD25A@4\" pad=\"12\"/>\n        <connect gate=\"G$1\" pin=\"VDD12_SW_OUT\" pad=\"13\"/>\n        <connect gate=\"G$1\" pin=\"VDD_SW_IN\" pad=\"14\"/>\n        <connect gate=\"G$1\" pin=\"VDD12_SW_FB\" pad=\"15\"/>\n        <connect gate=\"G$1\" pin=\"EECS/GPIO0\" pad=\"16\"/>\n        <connect gate=\"G$1\" pin=\"EEDI/GPIO1\" pad=\"17\"/>\n        <connect gate=\"G$1\" pin=\"EEDO/LED0/GPIO2\" pad=\"18\"/>\n        <connect gate=\"G$1\" pin=\"EECLK/LED1/GPIO3\" pad=\"19\"/>\n        <connect gate=\"G$1\" pin=\"VDDVARIO\" pad=\"20\"/>\n        <connect gate=\"G$1\" pin=\"VDD12CORE\" pad=\"21\"/>\n        <connect gate=\"G$1\" pin=\"PME_N/GPIO4\" pad=\"22\"/>\n        <connect gate=\"G$1\" pin=\"VBUS_DET\" pad=\"23\"/>\n        <connect gate=\"G$1\" pin=\"SUSPEND_N/LED2/GPIO5\" pad=\"24\"/>\n        <connect gate=\"G$1\" pin=\"VSS\" pad=\"49\"/>\n        <connect gate=\"G$1\" pin=\"REF_FILT\" pad=\"48\"/>\n        <connect gate=\"G$1\" pin=\"REF_REXT\" pad=\"47\"/>\n        <connect gate=\"G$1\" pin=\"VDD33_REG_IN\" pad=\"46\"/>\n        <connect gate=\"G$1\" pin=\"VDD25_REG_OUT\" pad=\"45\"/>\n        <connect gate=\"G$1\" pin=\"VDD12A\" pad=\"44\"/>\n        <connect gate=\"G$1\" pin=\"PME_MODE/GPIO7\" pad=\"43\"/>\n        <connect gate=\"G$1\" pin=\"VDD12CORE@2\" pad=\"42\"/>\n        <connect gate=\"G$1\" pin=\"XO\" pad=\"41\"/>\n        <connect gate=\"G$1\" pin=\"XI\" pad=\"40\"/>\n        <connect gate=\"G$1\" pin=\"VDDVARIO@2\" pad=\"39\"/>\n        <connect gate=\"G$1\" pin=\"VDD33A\" pad=\"38\"/>\n        <connect gate=\"G$1\" pin=\"USBRBIAS\" pad=\"37\"/>\n        <connect gate=\"G$1\" pin=\"VDDVARIO@3\" pad=\"36\"/>\n        <connect gate=\"G$1\" pin=\"RESET_N/PME_CLEAR\" pad=\"35\"/>\n        <connect gate=\"G$1\" pin=\"TEST\" pad=\"34\"/>\n        <connect gate=\"G$1\" pin=\"LED3/GPIO6\" pad=\"33\"/>\n        <connect gate=\"G$1\" pin=\"USB3_RXDM\" pad=\"32\"/>\n        <connect gate=\"G$1\" pin=\"USB3_RXDP\" pad=\"31\"/>\n        <connect gate=\"G$1\" pin=\"VDD12A@2\" pad=\"30\"/>\n        <connect gate=\"G$1\" pin=\"USB3_TXDM\" pad=\"29\"/>\n        <connect gate=\"G$1\" pin=\"USB3_TXDP\" pad=\"28\"/>\n        <connect gate=\"G$1\" pin=\"USB2_DM\" pad=\"27\"/>\n        <connect gate=\"G$1\" pin=\"USB2_DP\" pad=\"26\"/>\n        <connect gate=\"G$1\" pin=\"VDD12A@3\" pad=\"25\"/>\n      </connects>\n\n      <technologies><technology name=\"\"/></technologies>\n    </device>\n  </devices>\n</deviceset></devicesets></library><library name=\"adom-resistor\"><packages><package name=\"0603WAF3300T5E\">\n  <description>0603WAF3300T5E</description>\n  <smd name=\"1\" x=\"-0.8000\" y=\"-0.0000\" dx=\"0.9000\" dy=\"1.0000\" layer=\"1\"/>\n  <smd name=\"2\" x=\"0.8000\" y=\"-0.0000\" dx=\"0.9000\" dy=\"1.0000\" layer=\"1\"/>\n  <wire x1=\"-1.1000\" y1=\"0.7000\" x2=\"-0.5000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <wire x1=\"-0.5000\" y1=\"0.7000\" x2=\"-0.5000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <wire x1=\"-0.5000\" y1=\"0.7000\" x2=\"-1.1000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <wire x1=\"-1.1000\" y1=\"0.7000\" x2=\"-1.1000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <text x=\"0.0000\" y=\"2.8000\" size=\"1.0000\" layer=\"25\" align=\"center\">&gt;NAME</text>\n  <text x=\"0.0000\" y=\"-2.8000\" size=\"1.0000\" layer=\"27\" align=\"center\">&gt;VALUE</text>\n</package></packages><packages3d><package3d name=\"0603WAF3300T5E\" urn=\"\" wip_urn=\"urn:adsk.wipprod:fs.file:vf.RRR?version=1\" locally_modified=\"yes\" type=\"model\"><packageinstances><packageinstance name=\"0603WAF3300T5E\"/></packageinstances></package3d></packages3d><symbols><symbol name=\"0603WAF3300T5E\">\n  <wire x1=\"-1.016\" y1=\"-2.54\" x2=\"1.016\" y2=\"-2.54\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"1.016\" y1=\"-2.54\" x2=\"1.016\" y2=\"2.54\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"1.016\" y1=\"2.54\" x2=\"-1.016\" y2=\"2.54\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"-1.016\" y1=\"2.54\" x2=\"-1.016\" y2=\"-2.54\" width=\"0.254\" layer=\"94\"/>\n  <text x=\"0\" y=\"0\" size=\"1.27\" layer=\"95\" align=\"bottom-center\">&gt;NAME</text>\n  <text x=\"0\" y=\"0\" size=\"1.27\" layer=\"96\" align=\"top-center\">&gt;VALUE</text>\n  <pin name=\"1\" x=\"0\" y=\"3.81\" length=\"short\" direction=\"pas\" rot=\"R270\"/>\n  <pin name=\"2\" x=\"0\" y=\"-3.81\" length=\"short\" direction=\"pas\" rot=\"R90\"/>\n</symbol></symbols><devicesets><deviceset name=\"0603WAF3300T5E\" prefix=\"R\">\n  <description>Resistor</description>\n  <gates>\n    <gate name=\"G$1\" symbol=\"0603WAF3300T5E\" x=\"0\" y=\"0\"/>\n  </gates>\n  <devices>\n    <device name=\"\" package=\"0603WAF3300T5E\">\n      <connects>\n        <connect gate=\"G$1\" pin=\"1\" pad=\"1\"/>\n        <connect gate=\"G$1\" pin=\"2\" pad=\"2\"/>\n      </connects>\n      <technologies>\n        <technology name=\"\">\n          <attribute name=\"MPN\" value=\"0603WAF3300T5E\" constant=\"no\"/>\n        </technology>\n      </technologies>\n    </device>\n  </devices>\n</deviceset></devicesets></library></libraries><attributes/><variantdefs/><classes><class number=\"0\" name=\"default\" width=\"0\" drill=\"0\"/></classes><parts><part name=\"U1\" library=\"Demo_Board\" deviceset=\"LAN7800\" device=\"\"/><part name=\"R1\" library=\"adom-resistor\" deviceset=\"0603WAF3300T5E\" device=\"\" value=\"330\"/></parts><sheets><sheet><plain><text x=\"0\" y=\"30.48\" size=\"2.54\" layer=\"97\">Adom generated test circuit: LAN7800</text></plain><instances><instance part=\"R1\" gate=\"G$1\" x=\"12.7\" y=\"12.7\"/><instance part=\"U1\" gate=\"G$1\" x=\"38.1\" y=\"12.7\"/></instances><busses/><nets><net name=\"N1\" class=\"0\"><segment><wire x1=\"17.78\" y1=\"12.7\" x2=\"25.4\" y2=\"12.7\" width=\"0.1524\" layer=\"91\"/><pinref part=\"R1\" gate=\"G$1\" pin=\"2\"/><pinref part=\"U1\" gate=\"G$1\" pin=\"TR0P\"/></segment></net><net name=\"VCC\" class=\"0\"><segment><wire x1=\"7.62\" y1=\"12.7\" x2=\"2.54\" y2=\"12.7\" width=\"0.1524\" layer=\"91\"/><pinref part=\"R1\" gate=\"G$1\" pin=\"1\"/></segment></net><net name=\"GND\" class=\"0\"><segment><pinref part=\"U1\" gate=\"G$1\" pin=\"TR0N\"/></segment></net></nets></sheet></sheets></schematic></drawing></eagle>\n",+   "brd": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE eagle SYSTEM \"eagle.dtd\">\n<eagle version=\"9.6.2\">\n<drawing>\n<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>\n<layer number=\"1\" name=\"Top\" color=\"4\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"16\" name=\"Bottom\" color=\"1\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"17\" name=\"Pads\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"18\" name=\"Vias\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"19\" name=\"Unrouted\" color=\"6\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"20\" name=\"Dimension\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"21\" name=\"tPlace\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"22\" name=\"bPlace\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"23\" name=\"tOrigins\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"24\" name=\"bOrigins\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"25\" name=\"tNames\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"26\" name=\"bNames\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"27\" name=\"tValues\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"28\" name=\"bValues\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"29\" name=\"tStop\" color=\"7\" fill=\"3\" visible=\"no\" active=\"yes\"/>\n<layer number=\"30\" name=\"bStop\" color=\"7\" fill=\"6\" visible=\"no\" active=\"yes\"/>\n<layer number=\"31\" name=\"tCream\" color=\"7\" fill=\"4\" visible=\"no\" active=\"yes\"/>\n<layer number=\"32\" name=\"bCream\" color=\"7\" fill=\"5\" visible=\"no\" active=\"yes\"/>\n<layer number=\"33\" name=\"tFinish\" color=\"6\" fill=\"3\" visible=\"no\" active=\"yes\"/>\n<layer number=\"34\" name=\"bFinish\" color=\"6\" fill=\"6\" visible=\"no\" active=\"yes\"/>\n<layer number=\"35\" name=\"tGlue\" color=\"7\" fill=\"4\" visible=\"no\" active=\"yes\"/>\n<layer number=\"36\" name=\"bGlue\" color=\"7\" fill=\"5\" visible=\"no\" active=\"yes\"/>\n<layer number=\"37\" name=\"tTest\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"38\" name=\"bTest\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"39\" name=\"tKeepout\" color=\"4\" fill=\"11\" visible=\"no\" active=\"yes\"/>\n<layer number=\"40\" name=\"bKeepout\" color=\"1\" fill=\"11\" visible=\"no\" active=\"yes\"/>\n<layer number=\"41\" name=\"tRestrict\" color=\"4\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"42\" name=\"bRestrict\" color=\"1\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"43\" name=\"vRestrict\" color=\"2\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"44\" name=\"Drills\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"45\" name=\"Holes\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"46\" name=\"Milling\" color=\"3\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"47\" name=\"Measures\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"48\" name=\"Document\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"49\" name=\"Reference\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"91\" name=\"Nets\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"92\" name=\"Busses\" color=\"1\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"93\" name=\"Pins\" color=\"2\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"94\" name=\"Symbols\" color=\"4\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"95\" name=\"Names\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"96\" name=\"Values\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"97\" name=\"Info\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"98\" name=\"Guide\" color=\"6\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n</layers><board><plain><wire x1=\"0\" y1=\"0\" x2=\"21.7\" y2=\"0\" width=\"0.2\" layer=\"20\"/><wire x1=\"21.7\" y1=\"0\" x2=\"21.7\" y2=\"14.0\" width=\"0.2\" layer=\"20\"/><wire x1=\"21.7\" y1=\"14.0\" x2=\"0\" y2=\"14.0\" width=\"0.2\" layer=\"20\"/><wire x1=\"0\" y1=\"14.0\" x2=\"0\" y2=\"0\" width=\"0.2\" layer=\"20\"/></plain><libraries><library name=\"Demo_Board\"><packages><package name=\"QFN-48_7x7mm\">\n  <description>QFN-48, 7 x 7 mm</description>\n  <smd name=\"1\" x=\"-3.5000\" y=\"2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"2\" x=\"-3.5000\" y=\"2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"3\" x=\"-3.5000\" y=\"1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"4\" x=\"-3.5000\" y=\"1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"5\" x=\"-3.5000\" y=\"0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"6\" x=\"-3.5000\" y=\"0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"7\" x=\"-3.5000\" y=\"-0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"8\" x=\"-3.5000\" y=\"-0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"9\" x=\"-3.5000\" y=\"-1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"10\" x=\"-3.5000\" y=\"-1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"11\" x=\"-3.5000\" y=\"-2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"12\" x=\"-3.5000\" y=\"-2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"13\" x=\"-2.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"14\" x=\"-2.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"15\" x=\"-1.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"16\" x=\"-1.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"17\" x=\"-0.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"18\" x=\"-0.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"19\" x=\"0.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"20\" x=\"0.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"21\" x=\"1.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"22\" x=\"1.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"23\" x=\"2.2500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"24\" x=\"2.7500\" y=\"-3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"25\" x=\"3.5000\" y=\"-2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"26\" x=\"3.5000\" y=\"-2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"27\" x=\"3.5000\" y=\"-1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"28\" x=\"3.5000\" y=\"-1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"29\" x=\"3.5000\" y=\"-0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"30\" x=\"3.5000\" y=\"-0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"31\" x=\"3.5000\" y=\"0.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"32\" x=\"3.5000\" y=\"0.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"33\" x=\"3.5000\" y=\"1.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"34\" x=\"3.5000\" y=\"1.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"35\" x=\"3.5000\" y=\"2.2500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"36\" x=\"3.5000\" y=\"2.7500\" dx=\"1.0000\" dy=\"0.2800\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"37\" x=\"2.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"38\" x=\"2.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"39\" x=\"1.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"40\" x=\"1.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"41\" x=\"0.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"42\" x=\"0.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"43\" x=\"-0.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"44\" x=\"-0.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"45\" x=\"-1.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"46\" x=\"-1.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"47\" x=\"-2.2500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"48\" x=\"-2.7500\" y=\"3.5000\" dx=\"0.2800\" dy=\"1.0000\" layer=\"1\" roundness=\"100\"/>\n  <smd name=\"49\" x=\"0.0000\" y=\"-0.0000\" dx=\"5.3000\" dy=\"5.3000\" layer=\"1\"/>\n  <circle x=\"-3.5000\" y=\"3.5000\" radius=\"0.0300\" width=\"0.0600\" layer=\"21\"/>\n  <polygon width=\"0.1000\" layer=\"51\">\n    <vertex x=\"-2.5000\" y=\"3.5000\"/>\n    <vertex x=\"3.5000\" y=\"3.5000\"/>\n    <vertex x=\"3.5000\" y=\"-3.5000\"/>\n    <vertex x=\"-3.5000\" y=\"-3.5000\"/>\n    <vertex x=\"-3.5000\" y=\"2.5000\"/>\n  </polygon>\n  <wire x1=\"3.7200\" y1=\"3.7200\" x2=\"3.7200\" y2=\"3.2800\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"3.2800\" y1=\"3.7200\" x2=\"3.7200\" y2=\"3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"3.7200\" x2=\"-3.2800\" y2=\"3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"3.2800\" x2=\"-3.7200\" y2=\"3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"-3.2800\" x2=\"-3.7200\" y2=\"-3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"3.7200\" y1=\"-3.7200\" x2=\"3.7200\" y2=\"-3.2800\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"3.2800\" y1=\"-3.7200\" x2=\"3.7200\" y2=\"-3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-3.7200\" y1=\"-3.7200\" x2=\"-3.2800\" y2=\"-3.7200\" width=\"0.2000\" layer=\"21\"/>\n  <wire x1=\"-4.1000\" y1=\"3.5200\" x2=\"-4.1200\" y2=\"3.4452\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1200\" y1=\"3.4452\" x2=\"-4.1747\" y2=\"3.3903\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1747\" y1=\"3.3903\" x2=\"-4.2494\" y2=\"3.3700\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.2494\" y1=\"3.3700\" x2=\"-4.3243\" y2=\"3.3897\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3243\" y1=\"3.3897\" x2=\"-4.3794\" y2=\"3.4441\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3794\" y1=\"3.4441\" x2=\"-4.4000\" y2=\"3.5188\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.4000\" y1=\"3.5188\" x2=\"-4.3806\" y2=\"3.5938\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3806\" y1=\"3.5938\" x2=\"-4.3264\" y2=\"3.6491\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.3264\" y1=\"3.6491\" x2=\"-4.2519\" y2=\"3.6700\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.2519\" y1=\"3.6700\" x2=\"-4.1768\" y2=\"3.6510\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1768\" y1=\"3.6510\" x2=\"-4.1213\" y2=\"3.5970\" width=\"0.3000\" layer=\"21\"/>\n  <wire x1=\"-4.1213\" y1=\"3.5970\" x2=\"-4.1000\" y2=\"3.5225\" width=\"0.3000\" layer=\"21\"/>\n  <text x=\"0\" y=\"4.600\" size=\"1.27\" layer=\"25\" align=\"bottom-center\">&gt;NAME</text>\n  <text x=\"0\" y=\"-4.600\" size=\"1.27\" layer=\"27\" align=\"top-center\">&gt;VALUE</text>\n</package></packages><packages3d><package3d name=\"LAN7800\" urn=\"\" wip_urn=\"urn:adsk.wipprod:fs.file:vf.GOLD0?version=1\" locally_modified=\"yes\" type=\"model\"><packageinstances><packageinstance name=\"QFN-48_7x7mm\"/></packageinstances></package3d></packages3d></library><library name=\"adom-resistor\"><packages><package name=\"0603WAF3300T5E\">\n  <description>0603WAF3300T5E</description>\n  <smd name=\"1\" x=\"-0.8000\" y=\"-0.0000\" dx=\"0.9000\" dy=\"1.0000\" layer=\"1\"/>\n  <smd name=\"2\" x=\"0.8000\" y=\"-0.0000\" dx=\"0.9000\" dy=\"1.0000\" layer=\"1\"/>\n  <wire x1=\"-1.1000\" y1=\"0.7000\" x2=\"-0.5000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <wire x1=\"-0.5000\" y1=\"0.7000\" x2=\"-0.5000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <wire x1=\"-0.5000\" y1=\"0.7000\" x2=\"-1.1000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <wire x1=\"-1.1000\" y1=\"0.7000\" x2=\"-1.1000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <text x=\"0.0000\" y=\"2.8000\" size=\"1.0000\" layer=\"25\" align=\"center\">&gt;NAME</text>\n  <text x=\"0.0000\" y=\"-2.8000\" size=\"1.0000\" layer=\"27\" align=\"center\">&gt;VALUE</text>\n</package></packages><packages3d><package3d name=\"0603WAF3300T5E\" urn=\"\" wip_urn=\"urn:adsk.wipprod:fs.file:vf.RRR?version=1\" locally_modified=\"yes\" type=\"model\"><packageinstances><packageinstance name=\"0603WAF3300T5E\"/></packageinstances></package3d></packages3d></library></libraries><attributes/><variantdefs/><classes><class number=\"0\" name=\"default\" width=\"0\" drill=\"0\"/></classes><designrules name=\"default\"/><autorouter/><elements><element name=\"R1\" library=\"adom-resistor\" package=\"0603WAF3300T5E\" value=\"330\" x=\"3.5\" y=\"7.0\" package3d_urn=\"urn:adsk.wipprod:fs.file:vf.RRR?version=1\"/><element name=\"U1\" library=\"Demo_Board\" package=\"QFN-48_7x7mm\" value=\"\" x=\"14.7\" y=\"7.0\" package3d_urn=\"urn:adsk.wipprod:fs.file:vf.GOLD0?version=1\"/></elements><signals><signal name=\"N1\"><contactref element=\"R1\" pad=\"2\"/><contactref element=\"U1\" pad=\"1\"/><wire x1=\"4.35\" y1=\"7.0\" x2=\"9.7\" y2=\"7.0\" width=\"0.3\" layer=\"1\"/></signal><signal name=\"VCC\"><contactref element=\"R1\" pad=\"1\"/></signal><signal name=\"GND\"><contactref element=\"U1\" pad=\"2\"/></signal></signals></board></drawing></eagle>\n"+  },+  {+   "deviceset": "CH340G",+   "solo": true,+   "urn": "urn:adsk.wipprod:fs.file:vf.GOLD1?version=1",+   "rUrn": "",+   "sch": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE eagle SYSTEM \"eagle.dtd\">\n<eagle version=\"9.6.2\">\n<drawing>\n<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=\"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><schematic xreflabel=\"%F%N/%S.%C%R\" xrefpart=\"/%S.%C%R\"><libraries><library name=\"Demo_Board\"><packages><package name=\"SOIC-16_3.9x9.9mm_P1.27mm\">\n  <description>SOIC-16, 3.9 x 9.9 mm, 1.27 mm pitch</description>\n  <smd name=\"1\" x=\"-2.4750\" y=\"4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"2\" x=\"-2.4750\" y=\"3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"3\" x=\"-2.4750\" y=\"1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"4\" x=\"-2.4750\" y=\"0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"5\" x=\"-2.4750\" y=\"-0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"6\" x=\"-2.4750\" y=\"-1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"7\" x=\"-2.4750\" y=\"-3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"8\" x=\"-2.4750\" y=\"-4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"9\" x=\"2.4750\" y=\"-4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"10\" x=\"2.4750\" y=\"-3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"11\" x=\"2.4750\" y=\"-1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"12\" x=\"2.4750\" y=\"-0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"13\" x=\"2.4750\" y=\"0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"14\" x=\"2.4750\" y=\"1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"15\" x=\"2.4750\" y=\"3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"16\" x=\"2.4750\" y=\"4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <polygon width=\"0.1200\" layer=\"21\">\n    <vertex x=\"-2.6000\" y=\"5.0100\"/>\n    <vertex x=\"-2.8400\" y=\"5.3400\"/>\n    <vertex x=\"-2.3600\" y=\"5.3400\"/>\n  </polygon>\n  <polygon width=\"0.1000\" layer=\"51\">\n    <vertex x=\"-0.9750\" y=\"4.9500\"/>\n    <vertex x=\"1.9500\" y=\"4.9500\"/>\n    <vertex x=\"1.9500\" y=\"-4.9500\"/>\n    <vertex x=\"-1.9500\" y=\"-4.9500\"/>\n    <vertex x=\"-1.9500\" y=\"3.9750\"/>\n  </polygon>\n  <wire x1=\"-2.0600\" y1=\"5.0600\" x2=\"2.0600\" y2=\"5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"-2.0600\" y1=\"5.0050\" x2=\"-2.0600\" y2=\"5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"-2.0600\" y1=\"-5.0600\" x2=\"-2.0600\" y2=\"-5.0050\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"2.0600\" y1=\"5.0600\" x2=\"2.0600\" y2=\"5.0050\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"2.0600\" y1=\"-5.0050\" x2=\"2.0600\" y2=\"-5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"2.0600\" y1=\"-5.0600\" x2=\"-2.0600\" y2=\"-5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <text x=\"0\" y=\"6.020\" size=\"1.27\" layer=\"25\" align=\"bottom-center\">&gt;NAME</text>\n  <text x=\"0\" y=\"-6.020\" size=\"1.27\" layer=\"27\" align=\"top-center\">&gt;VALUE</text>\n</package></packages><packages3d><package3d name=\"CH340G\" urn=\"\" wip_urn=\"urn:adsk.wipprod:fs.file:vf.GOLD1?version=1\" locally_modified=\"yes\" type=\"model\"><packageinstances><packageinstance name=\"SOIC-16_3.9x9.9mm_P1.27mm\"/></packageinstances></package3d></packages3d><symbols><symbol name=\"CH340G\">\n  <description>USB serial converter, UART, SOIC-16</description>\n  <wire x1=\"-12.7\" y1=\"15.239999999999998\" x2=\"12.7\" y2=\"15.239999999999998\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"12.7\" y1=\"15.239999999999998\" x2=\"12.7\" y2=\"-15.239999999999998\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"12.7\" y1=\"-15.239999999999998\" x2=\"-12.7\" y2=\"-15.239999999999998\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"-12.7\" y1=\"-15.239999999999998\" x2=\"-12.7\" y2=\"15.239999999999998\" width=\"0.254\" layer=\"94\"/>\n  <text x=\"-5.0800\" y=\"13.9700\" size=\"1.27\" layer=\"95\" align=\"center\">&gt;NAME</text>\n  <text x=\"1.2700\" y=\"13.9700\" size=\"1.27\" layer=\"96\" align=\"center\">&gt;VALUE</text>\n  <pin name=\"GND\" x=\"-17.78\" y=\"-7.620000000000001\" length=\"middle\" direction=\"pwr\"/>\n  <pin name=\"TXD\" x=\"17.78\" y=\"12.7\" length=\"middle\" direction=\"out\" rot=\"R180\"/>\n  <pin name=\"RXD\" x=\"-17.78\" y=\"10.16\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"V3\" x=\"-17.78\" y=\"-10.16\" length=\"middle\" direction=\"out\"/>\n  <pin name=\"UD+\" x=\"17.78\" y=\"0\" length=\"middle\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"UD-\" x=\"17.78\" y=\"-2.540000000000001\" length=\"middle\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"XI\" x=\"-17.78\" y=\"7.619999999999999\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"XO\" x=\"17.78\" y=\"10.16\" length=\"middle\" direction=\"out\" rot=\"R180\"/>\n  <pin name=\"CTS\" x=\"-17.78\" y=\"5.079999999999999\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"DSR\" x=\"-17.78\" y=\"0\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"RI\" x=\"-17.78\" y=\"-2.540000000000001\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"DCD\" x=\"-17.78\" y=\"2.539999999999999\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"DTR\" x=\"17.78\" y=\"7.619999999999999\" length=\"middle\" direction=\"out\" rot=\"R180\"/>\n  <pin name=\"RTS\" x=\"17.78\" y=\"5.079999999999999\" length=\"middle\" direction=\"out\" rot=\"R180\"/>\n  <pin name=\"R232\" x=\"-17.78\" y=\"12.7\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"VCC\" x=\"-17.78\" y=\"-12.7\" length=\"middle\" direction=\"pwr\"/>\n</symbol></symbols><devicesets><deviceset name=\"CH340G\" prefix=\"U\">\n  <description>USB serial converter, UART, SOIC-16</description>\n  <gates>\n    <gate name=\"G$1\" symbol=\"CH340G\" x=\"0\" y=\"0\"/>\n  </gates>\n  <devices>\n    <device name=\"\" package=\"SOIC-16_3.9x9.9mm_P1.27mm\">\n      <connects>\n        <connect gate=\"G$1\" pin=\"GND\" pad=\"1\"/>\n        <connect gate=\"G$1\" pin=\"TXD\" pad=\"2\"/>\n        <connect gate=\"G$1\" pin=\"RXD\" pad=\"3\"/>\n        <connect gate=\"G$1\" pin=\"V3\" pad=\"4\"/>\n        <connect gate=\"G$1\" pin=\"UD+\" pad=\"5\"/>\n        <connect gate=\"G$1\" pin=\"UD-\" pad=\"6\"/>\n        <connect gate=\"G$1\" pin=\"XI\" pad=\"7\"/>\n        <connect gate=\"G$1\" pin=\"XO\" pad=\"8\"/>\n        <connect gate=\"G$1\" pin=\"CTS\" pad=\"9\"/>\n        <connect gate=\"G$1\" pin=\"DSR\" pad=\"10\"/>\n        <connect gate=\"G$1\" pin=\"RI\" pad=\"11\"/>\n        <connect gate=\"G$1\" pin=\"DCD\" pad=\"12\"/>\n        <connect gate=\"G$1\" pin=\"DTR\" pad=\"13\"/>\n        <connect gate=\"G$1\" pin=\"RTS\" pad=\"14\"/>\n        <connect gate=\"G$1\" pin=\"R232\" pad=\"15\"/>\n        <connect gate=\"G$1\" pin=\"VCC\" pad=\"16\"/>\n      </connects>\n\n      <technologies><technology name=\"\"/></technologies>\n    </device>\n  </devices>\n</deviceset></devicesets></library></libraries><attributes/><variantdefs/><classes><class number=\"0\" name=\"default\" width=\"0\" drill=\"0\"/></classes><parts><part name=\"U1\" library=\"Demo_Board\" deviceset=\"CH340G\" device=\"\"/></parts><sheets><sheet><plain><text x=\"0\" y=\"25.4\" size=\"2.54\" layer=\"97\">CH340G - Adom component demo</text></plain><instances><instance part=\"U1\" gate=\"G$1\" x=\"25.4\" y=\"12.7\"/></instances><busses/><nets/></sheet></sheets></schematic></drawing></eagle>\n",+   "brd": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE eagle SYSTEM \"eagle.dtd\">\n<eagle version=\"9.6.2\">\n<drawing>\n<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>\n<layer number=\"1\" name=\"Top\" color=\"4\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"16\" name=\"Bottom\" color=\"1\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"17\" name=\"Pads\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"18\" name=\"Vias\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"19\" name=\"Unrouted\" color=\"6\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"20\" name=\"Dimension\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"21\" name=\"tPlace\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"22\" name=\"bPlace\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"23\" name=\"tOrigins\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"24\" name=\"bOrigins\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"25\" name=\"tNames\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"26\" name=\"bNames\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"27\" name=\"tValues\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"28\" name=\"bValues\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"29\" name=\"tStop\" color=\"7\" fill=\"3\" visible=\"no\" active=\"yes\"/>\n<layer number=\"30\" name=\"bStop\" color=\"7\" fill=\"6\" visible=\"no\" active=\"yes\"/>\n<layer number=\"31\" name=\"tCream\" color=\"7\" fill=\"4\" visible=\"no\" active=\"yes\"/>\n<layer number=\"32\" name=\"bCream\" color=\"7\" fill=\"5\" visible=\"no\" active=\"yes\"/>\n<layer number=\"33\" name=\"tFinish\" color=\"6\" fill=\"3\" visible=\"no\" active=\"yes\"/>\n<layer number=\"34\" name=\"bFinish\" color=\"6\" fill=\"6\" visible=\"no\" active=\"yes\"/>\n<layer number=\"35\" name=\"tGlue\" color=\"7\" fill=\"4\" visible=\"no\" active=\"yes\"/>\n<layer number=\"36\" name=\"bGlue\" color=\"7\" fill=\"5\" visible=\"no\" active=\"yes\"/>\n<layer number=\"37\" name=\"tTest\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"38\" name=\"bTest\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"39\" name=\"tKeepout\" color=\"4\" fill=\"11\" visible=\"no\" active=\"yes\"/>\n<layer number=\"40\" name=\"bKeepout\" color=\"1\" fill=\"11\" visible=\"no\" active=\"yes\"/>\n<layer number=\"41\" name=\"tRestrict\" color=\"4\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"42\" name=\"bRestrict\" color=\"1\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"43\" name=\"vRestrict\" color=\"2\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"44\" name=\"Drills\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"45\" name=\"Holes\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"46\" name=\"Milling\" color=\"3\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"47\" name=\"Measures\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"48\" name=\"Document\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"49\" name=\"Reference\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"91\" name=\"Nets\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"92\" name=\"Busses\" color=\"1\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"93\" name=\"Pins\" color=\"2\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"94\" name=\"Symbols\" color=\"4\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"95\" name=\"Names\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"96\" name=\"Values\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"97\" name=\"Info\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"98\" name=\"Guide\" color=\"6\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n</layers><board><plain><wire x1=\"0\" y1=\"0\" x2=\"12.9\" y2=\"0\" width=\"0.2\" layer=\"20\"/><wire x1=\"12.9\" y1=\"0\" x2=\"12.9\" y2=\"16.84\" width=\"0.2\" layer=\"20\"/><wire x1=\"12.9\" y1=\"16.84\" x2=\"0\" y2=\"16.84\" width=\"0.2\" layer=\"20\"/><wire x1=\"0\" y1=\"16.84\" x2=\"0\" y2=\"0\" width=\"0.2\" layer=\"20\"/></plain><libraries><library name=\"Demo_Board\"><packages><package name=\"SOIC-16_3.9x9.9mm_P1.27mm\">\n  <description>SOIC-16, 3.9 x 9.9 mm, 1.27 mm pitch</description>\n  <smd name=\"1\" x=\"-2.4750\" y=\"4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"2\" x=\"-2.4750\" y=\"3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"3\" x=\"-2.4750\" y=\"1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"4\" x=\"-2.4750\" y=\"0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"5\" x=\"-2.4750\" y=\"-0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"6\" x=\"-2.4750\" y=\"-1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"7\" x=\"-2.4750\" y=\"-3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"8\" x=\"-2.4750\" y=\"-4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"9\" x=\"2.4750\" y=\"-4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"10\" x=\"2.4750\" y=\"-3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"11\" x=\"2.4750\" y=\"-1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"12\" x=\"2.4750\" y=\"-0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"13\" x=\"2.4750\" y=\"0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"14\" x=\"2.4750\" y=\"1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"15\" x=\"2.4750\" y=\"3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"16\" x=\"2.4750\" y=\"4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <polygon width=\"0.1200\" layer=\"21\">\n    <vertex x=\"-2.6000\" y=\"5.0100\"/>\n    <vertex x=\"-2.8400\" y=\"5.3400\"/>\n    <vertex x=\"-2.3600\" y=\"5.3400\"/>\n  </polygon>\n  <polygon width=\"0.1000\" layer=\"51\">\n    <vertex x=\"-0.9750\" y=\"4.9500\"/>\n    <vertex x=\"1.9500\" y=\"4.9500\"/>\n    <vertex x=\"1.9500\" y=\"-4.9500\"/>\n    <vertex x=\"-1.9500\" y=\"-4.9500\"/>\n    <vertex x=\"-1.9500\" y=\"3.9750\"/>\n  </polygon>\n  <wire x1=\"-2.0600\" y1=\"5.0600\" x2=\"2.0600\" y2=\"5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"-2.0600\" y1=\"5.0050\" x2=\"-2.0600\" y2=\"5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"-2.0600\" y1=\"-5.0600\" x2=\"-2.0600\" y2=\"-5.0050\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"2.0600\" y1=\"5.0600\" x2=\"2.0600\" y2=\"5.0050\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"2.0600\" y1=\"-5.0050\" x2=\"2.0600\" y2=\"-5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"2.0600\" y1=\"-5.0600\" x2=\"-2.0600\" y2=\"-5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <text x=\"0\" y=\"6.020\" size=\"1.27\" layer=\"25\" align=\"bottom-center\">&gt;NAME</text>\n  <text x=\"0\" y=\"-6.020\" size=\"1.27\" layer=\"27\" align=\"top-center\">&gt;VALUE</text>\n</package></packages><packages3d><package3d name=\"CH340G\" urn=\"\" wip_urn=\"urn:adsk.wipprod:fs.file:vf.GOLD1?version=1\" locally_modified=\"yes\" type=\"model\"><packageinstances><packageinstance name=\"SOIC-16_3.9x9.9mm_P1.27mm\"/></packageinstances></package3d></packages3d></library></libraries><attributes/><variantdefs/><classes><class number=\"0\" name=\"default\" width=\"0\" drill=\"0\"/></classes><designrules name=\"default\"/><autorouter/><elements><element name=\"U1\" library=\"Demo_Board\" package=\"SOIC-16_3.9x9.9mm_P1.27mm\" value=\"\" x=\"6.45\" y=\"8.42\" package3d_urn=\"urn:adsk.wipprod:fs.file:vf.GOLD1?version=1\"/></elements><signals/></board></drawing></eagle>\n"+  },+  {+   "deviceset": "CH340G",+   "solo": false,+   "urn": "urn:adsk.wipprod:fs.file:vf.GOLD1?version=1",+   "rUrn": "urn:adsk.wipprod:fs.file:vf.RRR?version=1",+   "sch": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE eagle SYSTEM \"eagle.dtd\">\n<eagle version=\"9.6.2\">\n<drawing>\n<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=\"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><schematic xreflabel=\"%F%N/%S.%C%R\" xrefpart=\"/%S.%C%R\"><libraries><library name=\"Demo_Board\"><packages><package name=\"SOIC-16_3.9x9.9mm_P1.27mm\">\n  <description>SOIC-16, 3.9 x 9.9 mm, 1.27 mm pitch</description>\n  <smd name=\"1\" x=\"-2.4750\" y=\"4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"2\" x=\"-2.4750\" y=\"3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"3\" x=\"-2.4750\" y=\"1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"4\" x=\"-2.4750\" y=\"0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"5\" x=\"-2.4750\" y=\"-0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"6\" x=\"-2.4750\" y=\"-1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"7\" x=\"-2.4750\" y=\"-3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"8\" x=\"-2.4750\" y=\"-4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"9\" x=\"2.4750\" y=\"-4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"10\" x=\"2.4750\" y=\"-3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"11\" x=\"2.4750\" y=\"-1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"12\" x=\"2.4750\" y=\"-0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"13\" x=\"2.4750\" y=\"0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"14\" x=\"2.4750\" y=\"1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"15\" x=\"2.4750\" y=\"3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"16\" x=\"2.4750\" y=\"4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <polygon width=\"0.1200\" layer=\"21\">\n    <vertex x=\"-2.6000\" y=\"5.0100\"/>\n    <vertex x=\"-2.8400\" y=\"5.3400\"/>\n    <vertex x=\"-2.3600\" y=\"5.3400\"/>\n  </polygon>\n  <polygon width=\"0.1000\" layer=\"51\">\n    <vertex x=\"-0.9750\" y=\"4.9500\"/>\n    <vertex x=\"1.9500\" y=\"4.9500\"/>\n    <vertex x=\"1.9500\" y=\"-4.9500\"/>\n    <vertex x=\"-1.9500\" y=\"-4.9500\"/>\n    <vertex x=\"-1.9500\" y=\"3.9750\"/>\n  </polygon>\n  <wire x1=\"-2.0600\" y1=\"5.0600\" x2=\"2.0600\" y2=\"5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"-2.0600\" y1=\"5.0050\" x2=\"-2.0600\" y2=\"5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"-2.0600\" y1=\"-5.0600\" x2=\"-2.0600\" y2=\"-5.0050\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"2.0600\" y1=\"5.0600\" x2=\"2.0600\" y2=\"5.0050\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"2.0600\" y1=\"-5.0050\" x2=\"2.0600\" y2=\"-5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"2.0600\" y1=\"-5.0600\" x2=\"-2.0600\" y2=\"-5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <text x=\"0\" y=\"6.020\" size=\"1.27\" layer=\"25\" align=\"bottom-center\">&gt;NAME</text>\n  <text x=\"0\" y=\"-6.020\" size=\"1.27\" layer=\"27\" align=\"top-center\">&gt;VALUE</text>\n</package></packages><packages3d><package3d name=\"CH340G\" urn=\"\" wip_urn=\"urn:adsk.wipprod:fs.file:vf.GOLD1?version=1\" locally_modified=\"yes\" type=\"model\"><packageinstances><packageinstance name=\"SOIC-16_3.9x9.9mm_P1.27mm\"/></packageinstances></package3d></packages3d><symbols><symbol name=\"CH340G\">\n  <description>USB serial converter, UART, SOIC-16</description>\n  <wire x1=\"-12.7\" y1=\"15.239999999999998\" x2=\"12.7\" y2=\"15.239999999999998\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"12.7\" y1=\"15.239999999999998\" x2=\"12.7\" y2=\"-15.239999999999998\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"12.7\" y1=\"-15.239999999999998\" x2=\"-12.7\" y2=\"-15.239999999999998\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"-12.7\" y1=\"-15.239999999999998\" x2=\"-12.7\" y2=\"15.239999999999998\" width=\"0.254\" layer=\"94\"/>\n  <text x=\"-5.0800\" y=\"13.9700\" size=\"1.27\" layer=\"95\" align=\"center\">&gt;NAME</text>\n  <text x=\"1.2700\" y=\"13.9700\" size=\"1.27\" layer=\"96\" align=\"center\">&gt;VALUE</text>\n  <pin name=\"GND\" x=\"-17.78\" y=\"-7.620000000000001\" length=\"middle\" direction=\"pwr\"/>\n  <pin name=\"TXD\" x=\"17.78\" y=\"12.7\" length=\"middle\" direction=\"out\" rot=\"R180\"/>\n  <pin name=\"RXD\" x=\"-17.78\" y=\"10.16\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"V3\" x=\"-17.78\" y=\"-10.16\" length=\"middle\" direction=\"out\"/>\n  <pin name=\"UD+\" x=\"17.78\" y=\"0\" length=\"middle\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"UD-\" x=\"17.78\" y=\"-2.540000000000001\" length=\"middle\" direction=\"io\" rot=\"R180\"/>\n  <pin name=\"XI\" x=\"-17.78\" y=\"7.619999999999999\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"XO\" x=\"17.78\" y=\"10.16\" length=\"middle\" direction=\"out\" rot=\"R180\"/>\n  <pin name=\"CTS\" x=\"-17.78\" y=\"5.079999999999999\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"DSR\" x=\"-17.78\" y=\"0\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"RI\" x=\"-17.78\" y=\"-2.540000000000001\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"DCD\" x=\"-17.78\" y=\"2.539999999999999\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"DTR\" x=\"17.78\" y=\"7.619999999999999\" length=\"middle\" direction=\"out\" rot=\"R180\"/>\n  <pin name=\"RTS\" x=\"17.78\" y=\"5.079999999999999\" length=\"middle\" direction=\"out\" rot=\"R180\"/>\n  <pin name=\"R232\" x=\"-17.78\" y=\"12.7\" length=\"middle\" direction=\"in\"/>\n  <pin name=\"VCC\" x=\"-17.78\" y=\"-12.7\" length=\"middle\" direction=\"pwr\"/>\n</symbol></symbols><devicesets><deviceset name=\"CH340G\" prefix=\"U\">\n  <description>USB serial converter, UART, SOIC-16</description>\n  <gates>\n    <gate name=\"G$1\" symbol=\"CH340G\" x=\"0\" y=\"0\"/>\n  </gates>\n  <devices>\n    <device name=\"\" package=\"SOIC-16_3.9x9.9mm_P1.27mm\">\n      <connects>\n        <connect gate=\"G$1\" pin=\"GND\" pad=\"1\"/>\n        <connect gate=\"G$1\" pin=\"TXD\" pad=\"2\"/>\n        <connect gate=\"G$1\" pin=\"RXD\" pad=\"3\"/>\n        <connect gate=\"G$1\" pin=\"V3\" pad=\"4\"/>\n        <connect gate=\"G$1\" pin=\"UD+\" pad=\"5\"/>\n        <connect gate=\"G$1\" pin=\"UD-\" pad=\"6\"/>\n        <connect gate=\"G$1\" pin=\"XI\" pad=\"7\"/>\n        <connect gate=\"G$1\" pin=\"XO\" pad=\"8\"/>\n        <connect gate=\"G$1\" pin=\"CTS\" pad=\"9\"/>\n        <connect gate=\"G$1\" pin=\"DSR\" pad=\"10\"/>\n        <connect gate=\"G$1\" pin=\"RI\" pad=\"11\"/>\n        <connect gate=\"G$1\" pin=\"DCD\" pad=\"12\"/>\n        <connect gate=\"G$1\" pin=\"DTR\" pad=\"13\"/>\n        <connect gate=\"G$1\" pin=\"RTS\" pad=\"14\"/>\n        <connect gate=\"G$1\" pin=\"R232\" pad=\"15\"/>\n        <connect gate=\"G$1\" pin=\"VCC\" pad=\"16\"/>\n      </connects>\n\n      <technologies><technology name=\"\"/></technologies>\n    </device>\n  </devices>\n</deviceset></devicesets></library><library name=\"adom-resistor\"><packages><package name=\"0603WAF3300T5E\">\n  <description>0603WAF3300T5E</description>\n  <smd name=\"1\" x=\"-0.8000\" y=\"-0.0000\" dx=\"0.9000\" dy=\"1.0000\" layer=\"1\"/>\n  <smd name=\"2\" x=\"0.8000\" y=\"-0.0000\" dx=\"0.9000\" dy=\"1.0000\" layer=\"1\"/>\n  <wire x1=\"-1.1000\" y1=\"0.7000\" x2=\"-0.5000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <wire x1=\"-0.5000\" y1=\"0.7000\" x2=\"-0.5000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <wire x1=\"-0.5000\" y1=\"0.7000\" x2=\"-1.1000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <wire x1=\"-1.1000\" y1=\"0.7000\" x2=\"-1.1000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <text x=\"0.0000\" y=\"2.8000\" size=\"1.0000\" layer=\"25\" align=\"center\">&gt;NAME</text>\n  <text x=\"0.0000\" y=\"-2.8000\" size=\"1.0000\" layer=\"27\" align=\"center\">&gt;VALUE</text>\n</package></packages><packages3d><package3d name=\"0603WAF3300T5E\" urn=\"\" wip_urn=\"urn:adsk.wipprod:fs.file:vf.RRR?version=1\" locally_modified=\"yes\" type=\"model\"><packageinstances><packageinstance name=\"0603WAF3300T5E\"/></packageinstances></package3d></packages3d><symbols><symbol name=\"0603WAF3300T5E\">\n  <wire x1=\"-1.016\" y1=\"-2.54\" x2=\"1.016\" y2=\"-2.54\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"1.016\" y1=\"-2.54\" x2=\"1.016\" y2=\"2.54\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"1.016\" y1=\"2.54\" x2=\"-1.016\" y2=\"2.54\" width=\"0.254\" layer=\"94\"/>\n  <wire x1=\"-1.016\" y1=\"2.54\" x2=\"-1.016\" y2=\"-2.54\" width=\"0.254\" layer=\"94\"/>\n  <text x=\"0\" y=\"0\" size=\"1.27\" layer=\"95\" align=\"bottom-center\">&gt;NAME</text>\n  <text x=\"0\" y=\"0\" size=\"1.27\" layer=\"96\" align=\"top-center\">&gt;VALUE</text>\n  <pin name=\"1\" x=\"0\" y=\"3.81\" length=\"short\" direction=\"pas\" rot=\"R270\"/>\n  <pin name=\"2\" x=\"0\" y=\"-3.81\" length=\"short\" direction=\"pas\" rot=\"R90\"/>\n</symbol></symbols><devicesets><deviceset name=\"0603WAF3300T5E\" prefix=\"R\">\n  <description>Resistor</description>\n  <gates>\n    <gate name=\"G$1\" symbol=\"0603WAF3300T5E\" x=\"0\" y=\"0\"/>\n  </gates>\n  <devices>\n    <device name=\"\" package=\"0603WAF3300T5E\">\n      <connects>\n        <connect gate=\"G$1\" pin=\"1\" pad=\"1\"/>\n        <connect gate=\"G$1\" pin=\"2\" pad=\"2\"/>\n      </connects>\n      <technologies>\n        <technology name=\"\">\n          <attribute name=\"MPN\" value=\"0603WAF3300T5E\" constant=\"no\"/>\n        </technology>\n      </technologies>\n    </device>\n  </devices>\n</deviceset></devicesets></library></libraries><attributes/><variantdefs/><classes><class number=\"0\" name=\"default\" width=\"0\" drill=\"0\"/></classes><parts><part name=\"U1\" library=\"Demo_Board\" deviceset=\"CH340G\" device=\"\"/><part name=\"R1\" library=\"adom-resistor\" deviceset=\"0603WAF3300T5E\" device=\"\" value=\"330\"/></parts><sheets><sheet><plain><text x=\"0\" y=\"30.48\" size=\"2.54\" layer=\"97\">Adom generated test circuit: CH340G</text></plain><instances><instance part=\"R1\" gate=\"G$1\" x=\"12.7\" y=\"12.7\"/><instance part=\"U1\" gate=\"G$1\" x=\"38.1\" y=\"12.7\"/></instances><busses/><nets><net name=\"N1\" class=\"0\"><segment><wire x1=\"17.78\" y1=\"12.7\" x2=\"25.4\" y2=\"12.7\" width=\"0.1524\" layer=\"91\"/><pinref part=\"R1\" gate=\"G$1\" pin=\"2\"/><pinref part=\"U1\" gate=\"G$1\" pin=\"GND\"/></segment></net><net name=\"VCC\" class=\"0\"><segment><wire x1=\"7.62\" y1=\"12.7\" x2=\"2.54\" y2=\"12.7\" width=\"0.1524\" layer=\"91\"/><pinref part=\"R1\" gate=\"G$1\" pin=\"1\"/></segment></net><net name=\"GND\" class=\"0\"><segment><pinref part=\"U1\" gate=\"G$1\" pin=\"TXD\"/></segment></net></nets></sheet></sheets></schematic></drawing></eagle>\n",+   "brd": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE eagle SYSTEM \"eagle.dtd\">\n<eagle version=\"9.6.2\">\n<drawing>\n<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>\n<layer number=\"1\" name=\"Top\" color=\"4\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"16\" name=\"Bottom\" color=\"1\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"17\" name=\"Pads\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"18\" name=\"Vias\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"19\" name=\"Unrouted\" color=\"6\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"20\" name=\"Dimension\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"21\" name=\"tPlace\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"22\" name=\"bPlace\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"23\" name=\"tOrigins\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"24\" name=\"bOrigins\" color=\"15\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"25\" name=\"tNames\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"26\" name=\"bNames\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"27\" name=\"tValues\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"28\" name=\"bValues\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"29\" name=\"tStop\" color=\"7\" fill=\"3\" visible=\"no\" active=\"yes\"/>\n<layer number=\"30\" name=\"bStop\" color=\"7\" fill=\"6\" visible=\"no\" active=\"yes\"/>\n<layer number=\"31\" name=\"tCream\" color=\"7\" fill=\"4\" visible=\"no\" active=\"yes\"/>\n<layer number=\"32\" name=\"bCream\" color=\"7\" fill=\"5\" visible=\"no\" active=\"yes\"/>\n<layer number=\"33\" name=\"tFinish\" color=\"6\" fill=\"3\" visible=\"no\" active=\"yes\"/>\n<layer number=\"34\" name=\"bFinish\" color=\"6\" fill=\"6\" visible=\"no\" active=\"yes\"/>\n<layer number=\"35\" name=\"tGlue\" color=\"7\" fill=\"4\" visible=\"no\" active=\"yes\"/>\n<layer number=\"36\" name=\"bGlue\" color=\"7\" fill=\"5\" visible=\"no\" active=\"yes\"/>\n<layer number=\"37\" name=\"tTest\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"38\" name=\"bTest\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"39\" name=\"tKeepout\" color=\"4\" fill=\"11\" visible=\"no\" active=\"yes\"/>\n<layer number=\"40\" name=\"bKeepout\" color=\"1\" fill=\"11\" visible=\"no\" active=\"yes\"/>\n<layer number=\"41\" name=\"tRestrict\" color=\"4\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"42\" name=\"bRestrict\" color=\"1\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"43\" name=\"vRestrict\" color=\"2\" fill=\"10\" visible=\"no\" active=\"yes\"/>\n<layer number=\"44\" name=\"Drills\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"45\" name=\"Holes\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"46\" name=\"Milling\" color=\"3\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"47\" name=\"Measures\" color=\"7\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"48\" name=\"Document\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"49\" name=\"Reference\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"91\" name=\"Nets\" color=\"2\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"92\" name=\"Busses\" color=\"1\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"93\" name=\"Pins\" color=\"2\" fill=\"1\" visible=\"no\" active=\"yes\"/>\n<layer number=\"94\" name=\"Symbols\" color=\"4\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"95\" name=\"Names\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"96\" name=\"Values\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"97\" name=\"Info\" color=\"7\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n<layer number=\"98\" name=\"Guide\" color=\"6\" fill=\"1\" visible=\"yes\" active=\"yes\"/>\n</layers><board><plain><wire x1=\"0\" y1=\"0\" x2=\"19.9\" y2=\"0\" width=\"0.2\" layer=\"20\"/><wire x1=\"19.9\" y1=\"0\" x2=\"19.9\" y2=\"16.84\" width=\"0.2\" layer=\"20\"/><wire x1=\"19.9\" y1=\"16.84\" x2=\"0\" y2=\"16.84\" width=\"0.2\" layer=\"20\"/><wire x1=\"0\" y1=\"16.84\" x2=\"0\" y2=\"0\" width=\"0.2\" layer=\"20\"/></plain><libraries><library name=\"Demo_Board\"><packages><package name=\"SOIC-16_3.9x9.9mm_P1.27mm\">\n  <description>SOIC-16, 3.9 x 9.9 mm, 1.27 mm pitch</description>\n  <smd name=\"1\" x=\"-2.4750\" y=\"4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"2\" x=\"-2.4750\" y=\"3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"3\" x=\"-2.4750\" y=\"1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"4\" x=\"-2.4750\" y=\"0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"5\" x=\"-2.4750\" y=\"-0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"6\" x=\"-2.4750\" y=\"-1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"7\" x=\"-2.4750\" y=\"-3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"8\" x=\"-2.4750\" y=\"-4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"9\" x=\"2.4750\" y=\"-4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"10\" x=\"2.4750\" y=\"-3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"11\" x=\"2.4750\" y=\"-1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"12\" x=\"2.4750\" y=\"-0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"13\" x=\"2.4750\" y=\"0.6350\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"14\" x=\"2.4750\" y=\"1.9050\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"15\" x=\"2.4750\" y=\"3.1750\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <smd name=\"16\" x=\"2.4750\" y=\"4.4450\" dx=\"1.9500\" dy=\"0.6000\" layer=\"1\" roundness=\"50\"/>\n  <polygon width=\"0.1200\" layer=\"21\">\n    <vertex x=\"-2.6000\" y=\"5.0100\"/>\n    <vertex x=\"-2.8400\" y=\"5.3400\"/>\n    <vertex x=\"-2.3600\" y=\"5.3400\"/>\n  </polygon>\n  <polygon width=\"0.1000\" layer=\"51\">\n    <vertex x=\"-0.9750\" y=\"4.9500\"/>\n    <vertex x=\"1.9500\" y=\"4.9500\"/>\n    <vertex x=\"1.9500\" y=\"-4.9500\"/>\n    <vertex x=\"-1.9500\" y=\"-4.9500\"/>\n    <vertex x=\"-1.9500\" y=\"3.9750\"/>\n  </polygon>\n  <wire x1=\"-2.0600\" y1=\"5.0600\" x2=\"2.0600\" y2=\"5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"-2.0600\" y1=\"5.0050\" x2=\"-2.0600\" y2=\"5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"-2.0600\" y1=\"-5.0600\" x2=\"-2.0600\" y2=\"-5.0050\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"2.0600\" y1=\"5.0600\" x2=\"2.0600\" y2=\"5.0050\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"2.0600\" y1=\"-5.0050\" x2=\"2.0600\" y2=\"-5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <wire x1=\"2.0600\" y1=\"-5.0600\" x2=\"-2.0600\" y2=\"-5.0600\" width=\"0.1200\" layer=\"21\"/>\n  <text x=\"0\" y=\"6.020\" size=\"1.27\" layer=\"25\" align=\"bottom-center\">&gt;NAME</text>\n  <text x=\"0\" y=\"-6.020\" size=\"1.27\" layer=\"27\" align=\"top-center\">&gt;VALUE</text>\n</package></packages><packages3d><package3d name=\"CH340G\" urn=\"\" wip_urn=\"urn:adsk.wipprod:fs.file:vf.GOLD1?version=1\" locally_modified=\"yes\" type=\"model\"><packageinstances><packageinstance name=\"SOIC-16_3.9x9.9mm_P1.27mm\"/></packageinstances></package3d></packages3d></library><library name=\"adom-resistor\"><packages><package name=\"0603WAF3300T5E\">\n  <description>0603WAF3300T5E</description>\n  <smd name=\"1\" x=\"-0.8000\" y=\"-0.0000\" dx=\"0.9000\" dy=\"1.0000\" layer=\"1\"/>\n  <smd name=\"2\" x=\"0.8000\" y=\"-0.0000\" dx=\"0.9000\" dy=\"1.0000\" layer=\"1\"/>\n  <wire x1=\"-1.1000\" y1=\"0.7000\" x2=\"-0.5000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <wire x1=\"-0.5000\" y1=\"0.7000\" x2=\"-0.5000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <wire x1=\"-0.5000\" y1=\"0.7000\" x2=\"-1.1000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <wire x1=\"-1.1000\" y1=\"0.7000\" x2=\"-1.1000\" y2=\"0.7000\" width=\"0.127\" layer=\"21\"/>\n  <text x=\"0.0000\" y=\"2.8000\" size=\"1.0000\" layer=\"25\" align=\"center\">&gt;NAME</text>\n  <text x=\"0.0000\" y=\"-2.8000\" size=\"1.0000\" layer=\"27\" align=\"center\">&gt;VALUE</text>\n</package></packages><packages3d><package3d name=\"0603WAF3300T5E\" urn=\"\" wip_urn=\"urn:adsk.wipprod:fs.file:vf.RRR?version=1\" locally_modified=\"yes\" type=\"model\"><packageinstances><packageinstance name=\"0603WAF3300T5E\"/></packageinstances></package3d></packages3d></library></libraries><attributes/><variantdefs/><classes><class number=\"0\" name=\"default\" width=\"0\" drill=\"0\"/></classes><designrules name=\"default\"/><autorouter/><elements><element name=\"R1\" library=\"adom-resistor\" package=\"0603WAF3300T5E\" value=\"330\" x=\"3.5\" y=\"8.42\" package3d_urn=\"urn:adsk.wipprod:fs.file:vf.RRR?version=1\"/><element name=\"U1\" library=\"Demo_Board\" package=\"SOIC-16_3.9x9.9mm_P1.27mm\" value=\"\" x=\"13.45\" y=\"8.42\" package3d_urn=\"urn:adsk.wipprod:fs.file:vf.GOLD1?version=1\"/></elements><signals><signal name=\"N1\"><contactref element=\"R1\" pad=\"2\"/><contactref element=\"U1\" pad=\"1\"/><wire x1=\"4.35\" y1=\"8.42\" x2=\"9.7\" y2=\"8.42\" width=\"0.3\" layer=\"1\"/></signal><signal name=\"VCC\"><contactref element=\"R1\" pad=\"1\"/></signal><signal name=\"GND\"><contactref element=\"U1\" pad=\"2\"/></signal></signals></board></drawing></eagle>\n"+  }+ ]+}\ No newline at end of file
rust/core/src/dialog_rules.jsonadded+209
@@ -0,0 +1,209 @@+{+ "rules": [+  {+   "needles": [+    "has errors and cannot be opened",+    "close the empty design file without saving"+   ],+   "category": "lbr_open_error",+   "resolution": "Fusion could not parse the library file. Click OK, close the leftover empty Untitled design WITHOUT saving, and fix the FILE - as of 1.9.128 fusion_open_lbr refuses unparseable libraries up front (lbr_invalid) so this modal should never appear for a bridge-issued open; a raw caller-staged file can still trip it."+  },+  {+   "needles": [+    "uploaded to your fusion hub",+    "packages are being uploaded",+    "being uploaded",+    "lose these changes"+   ],+   "category": "upload_in_progress",+   "resolution": "DATA LOSS RISK. Fusion is still uploading 3D package(s) to the Hub. Do NOT click Yes / do NOT close - you will LOSE the uploaded packages and any unsaved bindings. Click No, then WAIT and poll until the upload finishes before closing or saveAs. See the fusion-cloud-save skill."+  },+  {+   "needles": [+    "cannot be saved while packages",+    "save was cancelled",+    "save cancelled"+   ],+   "category": "save_blocked_by_upload",+   "resolution": "saveAs was refused because 3D packages are still uploading to the Hub (this also throws InternalValidationError). Not fatal: wait for the upload to drain, then retry the saveAs and poll past it. See the fusion-cloud-save skill."+  },+  {+   "needles": [+    "needs to update",+    "update is available",+    "software update",+    "new update"+   ],+   "category": "update_nag",+   "resolution": "Fusion is prompting to update itself. Do NOT auto-confirm (it can start an update mid-automation). Dismiss it on the desktop or let Fusion update, then retry. A pending update is also a common cause of AdomBridge add-in crashes (add-in/host version drift), so clearing it often fixes those too."+  },+  {+   "needles": [+    "select electronics design",+    "multiple electronics design",+    "linked to multiple"+   ],+   "category": "linked_design_picker",+   "resolution": "This file links to multiple Electronics designs. The chooser is a CEF/web modal whose list is NOT keyboard- or Win32-navigable (SendInput reaches only the native Cancel/OK), so it can't be resolved headlessly today \u2014 select the design on the desktop. (Headless fix tracked: have the add-in open the specific linked design via the Fusion API, avoiding the picker entirely.)"+  },+  {+   "needles": [+    "recovery",+    "recover unsaved",+    "document recovery"+   ],+   "category": "recovery",+   "resolution": "Document Recovery prompt. Call fusion_dismiss_recovery, or fusion_relocate_recovery BEFORE fusion_start to prevent it."+  },+  {+   "needles": [+    "save changes",+    "save document",+    "do you want to save",+    "unsaved changes",+    "save"+   ],+   "category": "save_changes",+   "resolution": "Unsaved-changes prompt. Use fusion_close_document (closes without the save modal), or fusion_send_key {\"key\":\"tab\"} then {\"key\":\"enter\"}."+  },+  {+   "needles": [+    "what do you want to design",+    "what to design"+   ],+   "category": "what_to_design",+   "resolution": "Fusion's start picker. fusion_send_key {\"key\":\"escape\"} to dismiss."+  },+  {+   "needles": [+    "create new footprint",+    "create new symbol",+    "create new device",+    "create new package",+    "create new library"+   ],+   "category": "create_confirm",+   "resolution": "Fusion is asking whether to CREATE an artifact we asked to open, which means the name does not exist in the library. Answering 'Yes' invents an empty artifact and hides the real problem, so the bridge answers NO and reports the missing name. Fix the NAME (fusion_show_* refuses up front with `available` listing what the .lbr actually holds)."+  },+  {+   "needles": [+    "caused fusion to close unexpectedly",+    "fusion error report",+    "a software problem has caused",+    "close unexpectedly"+   ],+   "category": "crash_report",+   "resolution": "Fusion CRASHED. The bridge closes this and relaunches Fusion - the add-in only loads at launch, so a relaunch is the only way back to drivable."+  },+  {+   "needles": [+    "session suspended",+    "suspended this session",+    "suspended by:"+   ],+   "category": "session_suspended_regrab",+   "resolution": "This box's Autodesk session was SUSPENDED by another machine taking the seat. The bridge clicks 'Check again' to regrab it (background UIA). Never click 'Shut Down' - that signs this box out."+  },+  {+   "needles": [+    "grid",+    "display style dots lines",+    "finest",+    "altdistance"+   ],+   "category": "settings_dialog_cancel",+   "resolution": "A Fusion electronics SETTINGS dialog (e.g. Grid) is open and blocking. It carries no data - Cancel it (WM_CLOSE / Cancel). Nothing we drive opens these deliberately; if it keeps recurring, something is injecting a stray GRID/settings command or keystroke."+  },+  {+   "needles": [+    "active sessions exceeded",+    "more active sessions",+    "more sessions running than are allowed",+    "sessions running than are allowed"+   ],+   "category": "session_conflict_decision",+   "resolution": "DECISION DIALOG - do NOT auto-pick. This Autodesk seat is already active on another machine; the options SUSPEND or SHUT DOWN Fusion THERE (risking that machine's unsaved work). fire a notify_user and ASK the user which option they want, then click it. (Suspend = pausable/resumable; Shut down = saves the other machine's work to a recovery file.)"+  },+  {+   "needles": [+    "suspend remote session"+   ],+   "category": "session_suspend_confirm",+   "resolution": "Confirmation of a chosen 'suspend the OTHER machine's Fusion'. Only click Continue if the user ALREADY chose suspend; otherwise Go Back and ASK. Never auto-confirm a seat action."+  },+  {+   "needles": [+    "fusion is already open",+    "multiple instances are not supported",+    "launch another fusion instance"+   ],+   "category": "already_open",+   "resolution": "Fusion is ALREADY running - a second launch was attempted. Click CANCEL (never Launch): Fusion is a singleton and the running instance is the one to drive. This usually means a prior fusion_stop/kill did not fully clear the old process before relaunch."+  },+  {+   "needles": [+    "welcome to fusion",+    "signing in - autodesk",+    "sign in - autodesk"+   ],+   "category": "signin_required",+   "resolution": "Autodesk sign-in needed (first run). NOTIFY the user, drive the 'Sign In' button (desktop_ui_click), fetch any email OTP via adom-google, and after the browser shows \"You're signed in\" click its 'Open Product' button - but NEVER auto-enter the password/2FA. See fusion-aps-signin."+  },+  {+   "needles": [+    "error launching streamed application",+    "missing or incomplete",+    "please re-install",+    "re-install the application"+   ],+   "category": "launch_error",+   "resolution": "Launch error from an INCOMPLETE webdeploy folder (missing FusionLauncher.exe.ini). Safe to dismiss (OK/close) - it is only an acknowledgement. Launch the COMPLETE production folder (the hash dir that HAS FusionLauncher.exe.ini); detect_fusion now prefers it."+  },+  {+   "needles": [+    "error",+    "cannot be opened",+    "has errors",+    "failed to",+    "could not",+    "invalid"+   ],+   "category": "operation_error",+   "resolution": "The last operation FAILED - Fusion is showing an Error dialog (the API call may still have returned ok because it opened an EMPTY design). READ the dialog screenshot for the exact message. Common case: '<file>.lbr has errors and cannot be opened' = the library is malformed (re-lint/regenerate; a frequent cause is a single UNNAMED symbol pin - EAGLE <pin name=''> + <connect pin=''> - name the pin from the KiCad pin NUMBER). The bridge already flipped success to False and dismissed the empty design; FIX the source file and retry. Do NOT report success."+  }+ ],+ "sets": {+  "FAILURE": [+   "operation_error"+  ],+  "DECISION": [+   "session_conflict_decision",+   "session_suspend_confirm"+  ],+  "AUTO_DISMISS": [+   "already_open",+   "crash_report",+   "create_confirm",+   "launch_error",+   "settings_dialog_cancel"+  ],+  "RELAUNCH": [+   "crash_report"+  ],+  "LAUNCH": [+   "already_open",+   "launch_error",+   "session_conflict_decision",+   "session_suspend_confirm",+   "signin_required"+  ]+ },+ "generic": {+  "category": "generic_modal_read_screenshot",+  "resolution": "Generic Fusion modal - its body is not Win32-readable, so a screenshot is attached: READ it and ANALYZE before acting. Do NOT blind-dismiss. If it mentions uploading / 'lose these changes' / 'sure you want to close' -> click No and wait for the Hub upload to drain (fusion-cloud-save). If it is the 'Select Electronics Design File' chooser during an open, its list is not keyboard/Win32-navigable; open the specific design by URN or select on the desktop."+ },+ "unknown": {+  "category": "unknown",+  "resolution": "Unrecognized modal - a screenshot is attached: READ it and ANALYZE before acting. Do NOT blindly dismiss (some modals lose work if confirmed wrong). Identify it from the screenshot, then take the work-preserving action."+ }+}\ No newline at end of file
rust/core/tests/dialogs_golden.rsadded+11
@@ -0,0 +1,11 @@+use serde_json::Value;++#[test]+fn title_classifier_matches_python() {+    let gold: Vec<Value> = serde_json::from_str(include_str!("golden/dialog_titles.json")).unwrap();+    for g in gold {+        let title = g["title"].as_str().unwrap();+        let got = fusion_core::dialogs::category_for_title(title).map(|(c, r)| serde_json::json!([c, r])).unwrap_or(Value::Null);+        assert_eq!(got, g["result"], "title {title:?}");+    }+}
rust/core/tests/golden/dialog_titles.jsonadded+178
@@ -0,0 +1,178 @@+[+ {+  "title": "Fusion",+  "result": [+   "generic_modal_read_screenshot",+   "Generic Fusion modal - its body is not Win32-readable, so a screenshot is attached: READ it and ANALYZE before acting. Do NOT blind-dismiss. If it mentions uploading / 'lose these changes' / 'sure you want to close' -> click No and wait for the Hub upload to drain (fusion-cloud-save). If it is the 'Select Electronics Design File' chooser during an open, its list is not keyboard/Win32-navigable; open the specific design by URN or select on the desktop."+  ]+ },+ {+  "title": "fusion360",+  "result": [+   "generic_modal_read_screenshot",+   "Generic Fusion modal - its body is not Win32-readable, so a screenshot is attached: READ it and ANALYZE before acting. Do NOT blind-dismiss. If it mentions uploading / 'lose these changes' / 'sure you want to close' -> click No and wait for the Hub upload to drain (fusion-cloud-save). If it is the 'Select Electronics Design File' chooser during an open, its list is not keyboard/Win32-navigable; open the specific design by URN or select on the desktop."+  ]+ },+ {+  "title": "Autodesk Fusion 360",+  "result": [+   "generic_modal_read_screenshot",+   "Generic Fusion modal - its body is not Win32-readable, so a screenshot is attached: READ it and ANALYZE before acting. Do NOT blind-dismiss. If it mentions uploading / 'lose these changes' / 'sure you want to close' -> click No and wait for the Hub upload to drain (fusion-cloud-save). If it is the 'Select Electronics Design File' chooser during an open, its list is not keyboard/Win32-navigable; open the specific design by URN or select on the desktop."+  ]+ },+ {+  "title": "Save changes to Demo_Board?",+  "result": [+   "save_changes",+   "Unsaved-changes prompt. Use fusion_close_document (closes without the save modal), or fusion_send_key {\"key\":\"tab\"} then {\"key\":\"enter\"}."+  ]+ },+ {+  "title": "Document Recovery",+  "result": [+   "recovery",+   "Document Recovery prompt. Call fusion_dismiss_recovery, or fusion_relocate_recovery BEFORE fusion_start to prevent it."+  ]+ },+ {+  "title": "Active Sessions Exceeded",+  "result": [+   "session_conflict_decision",+   "DECISION DIALOG - do NOT auto-pick. This Autodesk seat is already active on another machine; the options SUSPEND or SHUT DOWN Fusion THERE (risking that machine's unsaved work). fire a notify_user and ASK the user which option they want, then click it. (Suspend = pausable/resumable; Shut down = saves the other machine's work to a recovery file.)"+  ]+ },+ {+  "title": "Suspend Remote Session",+  "result": [+   "session_suspend_confirm",+   "Confirmation of a chosen 'suspend the OTHER machine's Fusion'. Only click Continue if the user ALREADY chose suspend; otherwise Go Back and ASK. Never auto-confirm a seat action."+  ]+ },+ {+  "title": "Fusion is already open",+  "result": [+   "already_open",+   "Fusion is ALREADY running - a second launch was attempted. Click CANCEL (never Launch): Fusion is a singleton and the running instance is the one to drive. This usually means a prior fusion_stop/kill did not fully clear the old process before relaunch."+  ]+ },+ {+  "title": "Signing in - Autodesk Fusion",+  "result": [+   "signin_required",+   "Autodesk sign-in needed (first run). NOTIFY the user, drive the 'Sign In' button (desktop_ui_click), fetch any email OTP via adom-google, and after the browser shows \"You're signed in\" click its 'Open Product' button - but NEVER auto-enter the password/2FA. See fusion-aps-signin."+  ]+ },+ {+  "title": "Error launching streamed application",+  "result": [+   "launch_error",+   "Launch error from an INCOMPLETE webdeploy folder (missing FusionLauncher.exe.ini). Safe to dismiss (OK/close) - it is only an acknowledgement. Launch the COMPLETE production folder (the hash dir that HAS FusionLauncher.exe.ini); detect_fusion now prefers it."+  ]+ },+ {+  "title": "Create new footprint 'X'?",+  "result": [+   "create_confirm",+   "Fusion is asking whether to CREATE an artifact we asked to open, which means the name does not exist in the library. Answering 'Yes' invents an empty artifact and hides the real problem, so the bridge answers NO and reports the missing name. Fix the NAME (fusion_show_* refuses up front with `available` listing what the .lbr actually holds)."+  ]+ },+ {+  "title": "Grid",+  "result": [+   "settings_dialog_cancel",+   "A Fusion electronics SETTINGS dialog (e.g. Grid) is open and blocking. It carries no data - Cancel it (WM_CLOSE / Cancel). Nothing we drive opens these deliberately; if it keeps recurring, something is injecting a stray GRID/settings command or keystroke."+  ]+ },+ {+  "title": "A software problem has caused Fusion to close unexpectedly",+  "result": [+   "crash_report",+   "Fusion CRASHED. The bridge closes this and relaunches Fusion - the add-in only loads at launch, so a relaunch is the only way back to drivable."+  ]+ },+ {+  "title": "Packages are being uploaded to your Fusion Hub",+  "result": [+   "upload_in_progress",+   "DATA LOSS RISK. Fusion is still uploading 3D package(s) to the Hub. Do NOT click Yes / do NOT close - you will LOSE the uploaded packages and any unsaved bindings. Click No, then WAIT and poll until the upload finishes before closing or saveAs. See the fusion-cloud-save skill."+  ]+ },+ {+  "title": "Cannot be saved while packages upload",+  "result": [+   "save_blocked_by_upload",+   "saveAs was refused because 3D packages are still uploading to the Hub (this also throws InternalValidationError). Not fatal: wait for the upload to drain, then retry the saveAs and poll past it. See the fusion-cloud-save skill."+  ]+ },+ {+  "title": "A software update is available",+  "result": [+   "update_nag",+   "Fusion is prompting to update itself. Do NOT auto-confirm (it can start an update mid-automation). Dismiss it on the desktop or let Fusion update, then retry. A pending update is also a common cause of AdomBridge add-in crashes (add-in/host version drift), so clearing it often fixes those too."+  ]+ },+ {+  "title": "Select Electronics Design",+  "result": [+   "linked_design_picker",+   "This file links to multiple Electronics designs. The chooser is a CEF/web modal whose list is NOT keyboard- or Win32-navigable (SendInput reaches only the native Cancel/OK), so it can't be resolved headlessly today \u2014 select the design on the desktop. (Headless fix tracked: have the add-in open the specific linked design via the Fusion API, avoiding the picker entirely.)"+  ]+ },+ {+  "title": "Session suspended by: other",+  "result": [+   "session_suspended_regrab",+   "This box's Autodesk session was SUSPENDED by another machine taking the seat. The bridge clicks 'Check again' to regrab it (background UIA). Never click 'Shut Down' - that signs this box out."+  ]+ },+ {+  "title": "Library.lbr has errors and cannot be opened",+  "result": [+   "lbr_open_error",+   "Fusion could not parse the library file. Click OK, close the leftover empty Untitled design WITHOUT saving, and fix the FILE - as of 1.9.128 fusion_open_lbr refuses unparseable libraries up front (lbr_invalid) so this modal should never appear for a bridge-issued open; a raw caller-staged file can still trip it."+  ]+ },+ {+  "title": "Could not open file",+  "result": [+   "operation_error",+   "The last operation FAILED - Fusion is showing an Error dialog (the API call may still have returned ok because it opened an EMPTY design). READ the dialog screenshot for the exact message. Common case: '<file>.lbr has errors and cannot be opened' = the library is malformed (re-lint/regenerate; a frequent cause is a single UNNAMED symbol pin - EAGLE <pin name=''> + <connect pin=''> - name the pin from the KiCad pin NUMBER). The bridge already flipped success to False and dismissed the empty design; FIX the source file and retry. Do NOT report success."+  ]+ },+ {+  "title": "Untitled",+  "result": [+   "unknown",+   "Unrecognized modal - a screenshot is attached: READ it and ANALYZE before acting. Do NOT blindly dismiss (some modals lose work if confirmed wrong). Identify it from the screenshot, then take the work-preserving action."+  ]+ },+ {+  "title": "",+  "result": null+ },+ {+  "title": "   ",+  "result": null+ },+ {+  "title": "WELCOME TO FUSION",+  "result": [+   "signin_required",+   "Autodesk sign-in needed (first run). NOTIFY the user, drive the 'Sign In' button (desktop_ui_click), fetch any email OTP via adom-google, and after the browser shows \"You're signed in\" click its 'Open Product' button - but NEVER auto-enter the password/2FA. See fusion-aps-signin."+  ]+ },+ {+  "title": "What do you want to design?",+  "result": [+   "what_to_design",+   "Fusion's start picker. fusion_send_key {\"key\":\"escape\"} to dismiss."+  ]+ },+ {+  "title": "Session Suspended",+  "result": [+   "session_suspended_regrab",+   "This box's Autodesk session was SUSPENDED by another machine taking the seat. The bridge clicks 'Check again' to regrab it (background UIA). Never click 'Shut Down' - that signs this box out."+  ]+ }+]\ No newline at end of file
tests/reports/daily-cron-2026-09-04.logadded+102
@@ -0,0 +1,102 @@+warmup: waking the bridge (unscored)...+  fusion_readiness                           PASS +  fusion_describe                            FAIL - verbs described but UNTRIAGED in test plan: ['fusion_apply_fusion_update', 'fusion_resolve_seat_dialog']+  fusion_get_app_state                       PASS +  fusion_search_cloud_files                  PASS +  fusion_walk_cloud_tree                     PASS +  fusion_aps_status                          PASS +  fusion_aps_get_browser                     PASS +  fusion_aps_search                          FAIL - expected >0 results+  fusion_aps_recent                          PASS +  fusion_aps_browse                          PASS +  fusion_aps_file_info                       FAIL - expected success, got error=No cloud file matching 'BQ25792'. code=None; missing field 'versionCount'+  fusion_aps_get                             PASS +  fusion_uninstall                           PASS +  fusion_set_seat_takeover                   PASS +  fusion_start                               PASS +  fusion_get_preferences                     PASS +  fusion_set_preference                      PASS +  fusion_mcp_status                          PASS +  fusion_set_auto_update                     PASS +  fusion_assembly_bom                        PASS +  fusion_dismiss_blocking_dialogs            PASS +  fusion_open_cloud_file                     FAIL - expected success, got error=Project 'Main' not found code=None+  fusion_show_schematic                      PASS +  fusion_show_2d_board                       PASS +  fusion_board_info                          PASS +  fusion_execute_text_command                FAIL - expected success, got error=Active document is 'ADOM-TEST-R-0402-0R', expected 'BQ25792'. code=wrong_document+  fusion_show_3d_board                       PASS +  fusion_inspect_bodies                      PASS +  fusion_physical_properties                 PASS +  fusion_get_design_info                     PASS +  fusion_get_parameters                      PASS +  fusion_document_info                       PASS +  fusion_run_modeling_script#guard           PASS +  fusion_assembly_bom#guard                  PASS +  fusion_run_modeling_script                 FAIL - expected success, got error=Active document is 'ADOM-TEST-R-0402-0R', expected 'BQ25792'. code=wrong_document+  fusion_close_window#noargs                 PASS +  fusion_cleanup_cloud_files#guard           PASS +  fusion_screenshot_fusion                   PASS +  fusion_state                               PASS +  fusion_demo_progress#unknown               PASS +  fusion_action_ledger                       PASS +  fusion_addin_status                        PASS +  fusion_alerts                              PASS +  fusion_verb_times                          PASS +  fusion_live_feed                           PASS +  fusion_prove_result                        PASS +  fusion_set_driving_badge                   PASS +  fusion_set_window_sizing                   PASS +  fusion_cancel_run                          FAIL - expected errorCode=None got unknown_run_id (error=no run with runId 'no-such-run' on this box)+  fusion_preflight_lbr                       FAIL - expected errorCode=None got lbr_preflight_failed (error=)+  fusion_library_parts                       FAIL - expected errorCode=None got library_unreadable (error=[Errno 2] No such file or directory: 'C:/nope/missing.lbr')+  focus_invariance                           PASS+cleanup: Fusion was already running before the run - leaving it (user's session).++Section coverage (John's product map, 2026-08-14):+  gui-driving                            14 pass / 1 fail (14 manual, 0 skip)  RED+  cad-3d-bom                             8 pass / 3 fail (2 manual, 0 skip)  RED+  mcp-server                             1 pass / 0 fail (1 manual, 0 skip)  green+  python-addin                           2 pass / 2 fail (1 manual, 0 skip)  RED+  aps                                    6 pass / 2 fail (11 manual, 0 skip)  RED+  auth-tokens                            2 pass / 0 fail (3 manual, 0 skip)  green+  exports                                0 pass / 0 fail (1 manual, 0 skip)  untested-this-tier+  bridge-lifecycle                       10 pass / 21 fail (13 manual, 0 skip)  RED++43 PASS, 29 FAIL (46 manual-tier, 0 skipped) -> /home/adom/project/adom-desktop-fusion-bridge/tests/reports/verb-test-2026-09-04_1152.json+  FAIL: fusion_apply_fusion_update - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_addin_gate - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_addin_restart_info - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_clean_incomplete_webdeploy - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_close_bridge_doc - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_close_docs_since - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_diagnose_addin_timeout - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_dialog_array - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_dismiss_recovery - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_docs_open - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_hung_check - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_part_metadata_report - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_post_verb - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_pre_verb - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_publish_library - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_sentinel - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_sweep_orphans - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_taskbar_progress - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_chain_verb_indicator - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_resolve_seat_dialog - described but untriaged in tests/run_verb_tests.py+  FAIL: fusion_describe - verbs described but UNTRIAGED in test plan: ['fusion_apply_fusion_update', 'fusion_resolve_seat_dialog']+  FAIL: fusion_aps_search - expected >0 results+  FAIL: fusion_aps_file_info - expected success, got error=No cloud file matching 'BQ25792'. code=None; missing field 'versionCount'+  FAIL: fusion_open_cloud_file - expected success, got error=Project 'Main' not found code=None+  FAIL: fusion_execute_text_command - expected success, got error=Active document is 'ADOM-TEST-R-0402-0R', expected 'BQ25792'. code=wrong_document+  FAIL: fusion_run_modeling_script - expected success, got error=Active document is 'ADOM-TEST-R-0402-0R', expected 'BQ25792'. code=wrong_document+  FAIL: fusion_cancel_run - expected errorCode=None got unknown_run_id (error=no run with runId 'no-such-run' on this box)+  FAIL: fusion_preflight_lbr - expected errorCode=None got lbr_preflight_failed (error=)+  FAIL: fusion_library_parts - expected errorCode=None got library_unreadable (error=[Errno 2] No such file or directory: 'C:/nope/missing.lbr')+error: unrecognized subcommand 'issue'++  tip: a similar subcommand exists: 'asset'++Usage: adom-wiki <COMMAND>++For more information, try '--help'.
tests/reports/daily-cron-history.txt+1
@@ -13,3 +13,4 @@ RED 2026-08-31 (exit 1) RED 2026-09-01 (exit 1) RED 2026-09-02 (exit 1) RED 2026-09-03 (exit 1)+RED 2026-09-04 (exit 1)
tests/reports/verb-test-2026-09-04_1152.jsonadded+819
@@ -0,0 +1,819 @@+{+ "date": "2026-09-04_1152",+ "target": "AdomLapper",+ "tier": "daily",+ "pass": 43,+ "fail": 29,+ "sections": {+  "bridge-lifecycle": {+   "PASS": 10,+   "FAIL": 21,+   "MANUAL": 13,+   "SKIP": 0+  },+  "gui-driving": {+   "PASS": 14,+   "FAIL": 1,+   "MANUAL": 14,+   "SKIP": 0+  },+  "aps": {+   "PASS": 6,+   "FAIL": 2,+   "MANUAL": 11,+   "SKIP": 0+  },+  "auth-tokens": {+   "PASS": 2,+   "FAIL": 0,+   "MANUAL": 3,+   "SKIP": 0+  },+  "mcp-server": {+   "PASS": 1,+   "FAIL": 0,+   "MANUAL": 1,+   "SKIP": 0+  },+  "cad-3d-bom": {+   "PASS": 8,+   "FAIL": 3,+   "MANUAL": 2,+   "SKIP": 0+  },+  "python-addin": {+   "PASS": 2,+   "FAIL": 2,+   "MANUAL": 1,+   "SKIP": 0+  },+  "exports": {+   "PASS": 0,+   "FAIL": 0,+   "MANUAL": 1,+   "SKIP": 0+  }+ },+ "results": [+  {+   "verb": "fusion_apply_fusion_update",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_addin_gate",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_addin_restart_info",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_clean_incomplete_webdeploy",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_close_bridge_doc",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_close_docs_since",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_diagnose_addin_timeout",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_dialog_array",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_dismiss_recovery",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_docs_open",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_hung_check",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_part_metadata_report",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_post_verb",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_pre_verb",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_publish_library",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_sentinel",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_sweep_orphans",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_taskbar_progress",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_chain_verb_indicator",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_resolve_seat_dialog",+   "status": "FAIL",+   "why": "described but untriaged in tests/run_verb_tests.py",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_readiness",+   "status": "PASS",+   "why": "",+   "sec": 3.1,+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_describe",+   "status": "FAIL",+   "why": "verbs described but UNTRIAGED in test plan: ['fusion_apply_fusion_update', 'fusion_resolve_seat_dialog']",+   "sec": 0.2,+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_get_app_state",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_search_cloud_files",+   "status": "PASS",+   "why": "",+   "sec": 2.9,+   "section": "aps"+  },+  {+   "verb": "fusion_walk_cloud_tree",+   "status": "PASS",+   "why": "",+   "sec": 2.4,+   "section": "aps"+  },+  {+   "verb": "fusion_aps_status",+   "status": "PASS",+   "why": "",+   "sec": 0.0,+   "section": "auth-tokens"+  },+  {+   "verb": "fusion_aps_get_browser",+   "status": "PASS",+   "why": "",+   "sec": 0.0,+   "section": "aps"+  },+  {+   "verb": "fusion_aps_search",+   "status": "FAIL",+   "why": "expected >0 results",+   "sec": 9.0,+   "section": "aps"+  },+  {+   "verb": "fusion_aps_recent",+   "status": "PASS",+   "why": "",+   "sec": 4.6,+   "section": "aps"+  },+  {+   "verb": "fusion_aps_browse",+   "status": "PASS",+   "why": "",+   "sec": 1.1,+   "section": "aps"+  },+  {+   "verb": "fusion_aps_file_info",+   "status": "FAIL",+   "why": "expected success, got error=No cloud file matching 'BQ25792'. code=None; missing field 'versionCount'",+   "sec": 5.6,+   "section": "aps"+  },+  {+   "verb": "fusion_aps_get",+   "status": "PASS",+   "why": "",+   "sec": 0.6,+   "section": "auth-tokens"+  },+  {+   "verb": "fusion_uninstall",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_set_seat_takeover",+   "status": "PASS",+   "why": "",+   "sec": 0.0,+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_aps_create_folder",+   "status": "MANUAL",+   "why": "needs projectId/parentFolderId of the test workspace",+   "section": "aps"+  },+  {+   "verb": "fusion_aps_upload",+   "status": "MANUAL",+   "why": "cloud write; exercised via build flows weekly",+   "section": "aps"+  },+  {+   "verb": "fusion_aps_set_client_id",+   "status": "MANUAL",+   "why": "would clobber org auth config",+   "section": "auth-tokens"+  },+  {+   "verb": "fusion_aps_set_browser",+   "status": "MANUAL",+   "why": "",+   "section": "aps"+  },+  {+   "verb": "fusion_aps_forget_browser",+   "status": "MANUAL",+   "why": "",+   "section": "aps"+  },+  {+   "verb": "fusion_aps_signin",+   "status": "MANUAL",+   "why": "opens a browser on the user's machine",+   "section": "auth-tokens"+  },+  {+   "verb": "fusion_start",+   "status": "PASS",+   "why": "",+   "sec": 3.3,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_get_preferences",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_set_preference",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_mcp_status",+   "status": "PASS",+   "why": "",+   "sec": 0.0,+   "section": "mcp-server"+  },+  {+   "verb": "fusion_mcp_enable",+   "status": "MANUAL",+   "why": "drives the prefs UI, takes foreground",+   "section": "mcp-server"+  },+  {+   "verb": "fusion_prefs_open",+   "status": "MANUAL",+   "why": "opens a dialog on the user's screen",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_prefs_close",+   "status": "MANUAL",+   "why": "",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_set_auto_update",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_assembly_bom",+   "status": "PASS",+   "why": "",+   "sec": 0.2,+   "section": "cad-3d-bom"+  },+  {+   "verb": "fusion_dismiss_blocking_dialogs",+   "status": "PASS",+   "why": "",+   "sec": 0.4,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_open_cloud_file",+   "status": "FAIL",+   "why": "expected success, got error=Project 'Main' not found code=None",+   "sec": 209.1,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_show_schematic",+   "status": "PASS",+   "why": "",+   "sec": 20.3,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_show_2d_board",+   "status": "PASS",+   "why": "",+   "sec": 13.4,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_board_info",+   "status": "PASS",+   "why": "",+   "sec": 0.2,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_execute_text_command",+   "status": "FAIL",+   "why": "expected success, got error=Active document is 'ADOM-TEST-R-0402-0R', expected 'BQ25792'. code=wrong_document",+   "sec": 3.3,+   "section": "python-addin"+  },+  {+   "verb": "fusion_show_3d_board",+   "status": "PASS",+   "why": "",+   "sec": 25.0,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_inspect_bodies",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "cad-3d-bom"+  },+  {+   "verb": "fusion_physical_properties",+   "status": "PASS",+   "why": "",+   "sec": 0.2,+   "section": "cad-3d-bom"+  },+  {+   "verb": "fusion_get_design_info",+   "status": "PASS",+   "why": "",+   "sec": 0.3,+   "section": "cad-3d-bom"+  },+  {+   "verb": "fusion_get_parameters",+   "status": "PASS",+   "why": "",+   "sec": 0.2,+   "section": "cad-3d-bom"+  },+  {+   "verb": "fusion_document_info",+   "status": "PASS",+   "why": "",+   "sec": 0.3,+   "section": "cad-3d-bom"+  },+  {+   "verb": "fusion_run_modeling_script#guard",+   "status": "PASS",+   "why": "",+   "sec": 3.5,+   "section": "python-addin"+  },+  {+   "verb": "fusion_assembly_bom#guard",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "cad-3d-bom"+  },+  {+   "verb": "fusion_run_modeling_script",+   "status": "FAIL",+   "why": "expected success, got error=Active document is 'ADOM-TEST-R-0402-0R', expected 'BQ25792'. code=wrong_document",+   "sec": 3.5,+   "section": "python-addin"+  },+  {+   "verb": "fusion_electron_select",+   "status": "MANUAL",+   "why": "selection state is user-visible",+   "section": "python-addin"+  },+  {+   "verb": "fusion_open_design",+   "status": "MANUAL",+   "why": "local-file open; superseded by cloud flows",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_close_window#noargs",+   "status": "PASS",+   "why": "",+   "sec": 0.0,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_close_document",+   "status": "MANUAL",+   "why": "",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_close_all_documents",+   "status": "MANUAL",+   "why": "would close the user's own tabs",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_export_obj",+   "status": "MANUAL",+   "why": "build/doc-type dependent (OBJ refused on the 2026-08-14 box); verify quarterly",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_export_fbx",+   "status": "MANUAL",+   "why": "build/doc-type dependent (OBJ refused on the 2026-08-14 box); verify quarterly",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_export_usdz",+   "status": "MANUAL",+   "why": "build/doc-type dependent (OBJ refused on the 2026-08-14 box); verify quarterly",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_export_dxf",+   "status": "MANUAL",+   "why": "build/doc-type dependent (OBJ refused on the 2026-08-14 box); verify quarterly",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_export_dwg",+   "status": "MANUAL",+   "why": "build/doc-type dependent (OBJ refused on the 2026-08-14 box); verify quarterly",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_export_skp",+   "status": "MANUAL",+   "why": "build/doc-type dependent (OBJ refused on the 2026-08-14 box); verify quarterly",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_set_design_rules",+   "status": "MANUAL",+   "why": "mutates the board's DRC rules",+   "section": "exports"+  },+  {+   "verb": "fusion_show_3d_package",+   "status": "MANUAL",+   "why": "enters Package3DEnvironment (exit needs Package3DStop + dialog); tour covers it; attach path in release rehearsals",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_bind_library_3d",+   "status": "MANUAL",+   "why": "cloud f3d mint per run; release rehearsals (needs signed-in session)",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_attach_3d_package",+   "status": "MANUAL",+   "why": "modal Save dialog needs a human eye",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_make_3d_package",+   "status": "MANUAL",+   "why": "cloud upload; run in release rehearsals",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_build_library_3d",+   "status": "MANUAL",+   "why": "long multi-part build; release rehearsals",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_cleanup_cloud_files#guard",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "aps"+  },+  {+   "verb": "fusion_cleanup_cloud_files",+   "status": "MANUAL",+   "why": "real cleanup takes explicit lineage urns; used by weekly build rehearsals",+   "section": "aps"+  },+  {+   "verb": "fusion_new_electronics_from_eagle",+   "status": "MANUAL",+   "why": "drives native dialogs",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_screenshot_fusion",+   "status": "PASS",+   "why": "",+   "sec": 1.4,+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_state",+   "status": "PASS",+   "why": "",+   "sec": 6.2,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_demo_progress#unknown",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_stop",+   "status": "MANUAL",+   "why": "lifecycle/human-wall verbs; manual tier",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_kill",+   "status": "MANUAL",+   "why": "lifecycle/human-wall verbs; manual tier",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_signin",+   "status": "MANUAL",+   "why": "lifecycle/human-wall verbs; manual tier",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_signin_2fa",+   "status": "MANUAL",+   "why": "lifecycle/human-wall verbs; manual tier",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_demo",+   "status": "MANUAL",+   "why": "lifecycle/human-wall verbs; manual tier",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_install_fusion",+   "status": "MANUAL",+   "why": "lifecycle/human-wall verbs; manual tier",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_notify_owner",+   "status": "MANUAL",+   "why": "lifecycle/human-wall verbs; manual tier",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_open_by_urn_note",+   "status": "MANUAL",+   "why": "lifecycle/human-wall verbs; manual tier",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_action_ledger",+   "status": "PASS",+   "why": "",+   "sec": 0.0,+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_addin_status",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "python-addin"+  },+  {+   "verb": "fusion_alerts",+   "status": "PASS",+   "why": "",+   "sec": 1.8,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_verb_times",+   "status": "PASS",+   "why": "",+   "sec": 0.2,+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_live_feed",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_prove_result",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "cad-3d-bom"+  },+  {+   "verb": "fusion_set_driving_badge",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_set_window_sizing",+   "status": "PASS",+   "why": "",+   "sec": 0.1,+   "section": "gui-driving"+  },+  {+   "verb": "fusion_cancel_run",+   "status": "FAIL",+   "why": "expected errorCode=None got unknown_run_id (error=no run with runId 'no-such-run' on this box)",+   "sec": 0.2,+   "section": "cad-3d-bom"+  },+  {+   "verb": "fusion_preflight_lbr",+   "status": "FAIL",+   "why": "expected errorCode=None got lbr_preflight_failed (error=)",+   "sec": 0.0,+   "section": "cad-3d-bom"+  },+  {+   "verb": "fusion_library_parts",+   "status": "FAIL",+   "why": "expected errorCode=None got library_unreadable (error=[Errno 2] No such file or directory: 'C:/nope/missing.lbr')",+   "sec": 0.0,+   "section": "cad-3d-bom"+  },+  {+   "verb": "fusion_create_library",+   "status": "MANUAL",+   "why": "the five-part drill covers it (fusion_install_library_bundle -> prove)",+   "section": "cad-3d-bom"+  },+  {+   "verb": "fusion_install_library_bundle",+   "status": "MANUAL",+   "why": "the five-part drill covers it; needs a bundle zip on the box",+   "section": "cad-3d-bom"+  },+  {+   "verb": "fusion_managed_library_create",+   "status": "MANUAL",+   "why": "creates a managed library on the hub (cloud write)",+   "section": "aps"+  },+  {+   "verb": "fusion_managed_library_link",+   "status": "MANUAL",+   "why": "drives LIBRARY.IO dialogs against the hub",+   "section": "aps"+  },+  {+   "verb": "fusion_managed_library_pull",+   "status": "MANUAL",+   "why": "drives LIBRARY.IO dialogs against the hub",+   "section": "aps"+  },+  {+   "verb": "fusion_managed_library_push",+   "status": "MANUAL",+   "why": "drives LIBRARY.IO dialogs; cloud write",+   "section": "aps"+  },+  {+   "verb": "fusion_managed_library_unlink",+   "status": "MANUAL",+   "why": "drives LIBRARY.IO dialogs against the hub",+   "section": "aps"+  },+  {+   "verb": "fusion_reset_workspace",+   "status": "MANUAL",+   "why": "closes the user's documents",+   "section": "gui-driving"+  },+  {+   "verb": "fusion_restart_for_addin",+   "status": "MANUAL",+   "why": "restarts Fusion",+   "section": "bridge-lifecycle"+  },+  {+   "verb": "fusion_save_to_cloud",+   "status": "MANUAL",+   "why": "cloud write; exercised by the drills",+   "section": "aps"+  },+  {+   "verb": "fusion_web_signin",+   "status": "MANUAL",+   "why": "opens a browser on the user's machine",+   "section": "auth-tokens"+  },+  {+   "verb": "focus_invariance",+   "status": "PASS",+   "why": "",+   "section": "gui-driving"+  }+ ],+ "durationSec": 324.3+}\ No newline at end of file
tools/exe-only-flip.shadded+33
@@ -0,0 +1,33 @@+#!/usr/bin/env bash+# Phase 4, the package flip (run ONLY on John's word): the release becomes the Rust exe alone.+#   - bridge.json: spawn.kind exe, entrypoint adom-fusion-bridge.exe, no python dependency+#   - tools/release-files.txt: the Python bridge and its helpers leave the zip (describe.py stays+#     a BUILD-time input for freeze-contract; the add-in tree and resources ship as before)+#   - tools/release.sh keeps its contract freeze and the exe build; the python import checks go+# Idempotent; prints what changed; commits nothing. Review the diff, then tools/release.sh.+set -euo pipefail+cd "$(dirname "$0")/.."+python3 - <<'PY'+import json, re, pathlib+b = pathlib.Path("bridge.json"); m = json.loads(b.read_text(encoding="utf-8"))+sp = m["spawn"]+sp.update({"kind": "exe", "entrypoint": "adom-fusion-bridge.exe", "killImageName": "adom-fusion-bridge.exe",+           "_hint": "spawn.kind exe: one sha256-verified binary, no interpreter provisioning. The Python bridge left the package in Phase 4 of the Rust port (2026-09); an owner pref of \"sidecar\" in ~/.adom/fusion-bridge/prefs.json is honoured only where server.py still sits beside the exe."})+m.get("dependencies", {}).pop("python", None)+b.write_text(json.dumps(m, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")+print("bridge.json: spawn.kind exe, python dependency dropped")+drop = {"server.py", "aps.py", "fusion_detect.py", "fusion_helper.py", "eagle_lbr.py", "timings.py", "library_bundle.py",+        "ab_client.py", "install_addin.py", "handlers/__init__.py", "handlers/close_fusion.py", "handlers/dialog_classify.py",+        "handlers/dismiss_recovery.py", "handlers/fusion_ui.py", "handlers/open_design.py", "handlers/taskbar_overlay.py", "start.bat"}+rf = pathlib.Path("tools/release-files.txt"); lines = [l for l in rf.read_text().splitlines() if l.strip()]+kept = [l for l in lines if l not in drop]+rf.write_text("\n".join(kept) + "\n"); print("release-files.txt: dropped", len(lines) - len(kept), "python files, kept", len(kept))+rs = pathlib.Path("tools/release.sh"); s = rs.read_text()+s2 = re.sub(r'^python3 -c "import ast; ast\.parse\(open\(\'server\.py\'\)\.read\(\)\)".*\n', '', s, flags=re.M)+s2 = re.sub(r'^python3 tools/shadow_check\.py server\.py.*\n', '', s2, flags=re.M)+s2 = re.sub(r'^python3 -c "import server".*\n', '', s2, flags=re.M)+s2 = re.sub(r'^python3 -c "import fusion_detect".*\n', '', s2, flags=re.M)+s2 = s2.replace('*server.py*fusion*', '*adom-fusion-bridge.exe*')+if s2 != s: rs.write_text(s2); print("release.sh: python import checks removed, process probe names the exe")+PY+git status --short | head -20
tools/release-files.txt−17
@@ -1,7 +1,5 @@ BRIDGE_VERSION LICENSE-ab_client.py-library_bundle.py addin/AdomBridge/AdomBridge.manifest addin/AdomBridge/AdomBridge.py addin/AdomBridge/commands/__init__.py@@ -32,30 +30,15 @@ addin/AdomBridge/resources/dru/AdomDefaults-jlcpcb-2layers-accurate.edru addin/AdomBridge/resources/dru/AdomDefaults-jlcpcb-4layers-accurate.edru addin/AdomBridge/resources/ulp/detect_layers.ulp adom-bridge-fusion-manifest.json-aps.py bridge.json describe.py-timings.py-eagle_lbr.py-fusion_detect.py-fusion_helper.py-handlers/__init__.py-handlers/close_fusion.py-handlers/dialog_classify.py-handlers/dismiss_recovery.py-handlers/fusion_ui.py-handlers/open_design.py install.sh-install_addin.py package.json resources/samples/0603WAF3300T5E.lbr resources/samples/0603WAF3300T5E.step resources/samples/ADS8588SIPM.fusion.lbr resources/samples/ADS8588SIPM.step-server.py-start.bat uninstall.sh-handlers/taskbar_overlay.py resources/adom-overlay-32.png dev-skills/fusion-auth-surfaces/SKILL.md addin/AdomBridge/commands/activity_palette.py
tools/rust-commit.shadded+11
@@ -0,0 +1,11 @@+#!/usr/bin/env bash+# Gate, then commit and push - never the other way round. Usage: tools/rust-commit.sh "message"+set -euo pipefail+cd "$(dirname "$0")/.."+bash tools/rust-ship.sh+git add -A+git commit -q -m "$1++Co-Authored-By: Claude Fable 5.1 <[email protected]>"+git push 2>&1 | tail -1+git log --oneline -1
tools/rust-ship.shadded+14
@@ -0,0 +1,14 @@+#!/usr/bin/env bash+# The gate before any Rust commit or deploy: both targets build, the tests pass, the guards pass.+# (2026-09-04: a `cargo build | grep error` pipeline hid a type error and a broken commit was pushed.)+set -euo pipefail+cd "$(dirname "$0")/../rust"+cargo build --quiet+# (2026-09-04 again: `cargo test | grep FAILED && exit 1 || true` under pipefail never exited - a+# failing cargo made the pipeline fail, so the && branch was skipped and a red test was pushed.)+cargo test --quiet >"${TMPDIR:-/tmp}/rust-ship-test.log" 2>&1 || { grep -E 'FAILED|panicked|error' "${TMPDIR:-/tmp}/rust-ship-test.log" | head -20; echo "TESTS FAILED"; exit 1; }+cargo build --release --quiet --target x86_64-pc-windows-gnu+cd ..+bash tools/check-portable.sh >/dev/null+bash tools/check-naming.sh >/dev/null+echo "rust-ship: linux build, tests, windows build, guards: all green"