[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"navigation":3,"url-settings":86,"blog-\u002Fblog\u002Fhow-to-extract-device-information-with-dart-ffi-on-windows":671,"blog-author-\u002Fblog\u002Fhow-to-extract-device-information-with-dart-ffi-on-windows":974,"i-material-symbols:arrow-back-rounded":989},{"id":4,"extension":5,"footer":6,"header":73,"meta":83,"stem":84,"__hash__":85},"navigation\u002Fdata\u002Fshared\u002Fnavigation.yml","yml",{"brand":7,"columns":13,"legal":63},{"name":8,"tagline":9,"downloadCta":10},"Pieces","The memory layer for modern work.",{"label":11,"href":12},"All downloads","\u002Fdownloads",[14,26,39,51],{"title":15,"links":16},"Product",[17,20,23],{"label":18,"href":19},"Pieces Desktop","\u002F",{"label":21,"href":22},"Pieces Enterprise","\u002Fenterprise",{"label":24,"href":25},"Pieces MCP","\u002Fmcp",{"title":27,"links":28},"Resources",[29,33,36],{"label":30,"href":31,"external":32},"Documentation","url:docs.home",true,{"label":34,"href":35},"Blog","\u002Fblog",{"label":37,"href":38,"external":32},"GitHub","url:github.org",{"title":40,"links":41},"Community",[42,45,48],{"label":43,"href":44,"external":32},"Discord","url:social.discord",{"label":46,"href":47,"external":32},"X \u002F Twitter","url:social.x",{"label":49,"href":50,"external":32},"LinkedIn","url:social.linkedin",{"title":52,"links":53},"Company",[54,57,60],{"label":55,"href":56},"About","\u002Fabout",{"label":58,"href":59},"Updates","\u002Fupdates",{"label":61,"href":62},"Contact","\u002Fcontact",[64,67,70],{"label":65,"href":66},"Privacy Policy","\u002Flegal\u002Fprivacy",{"label":68,"href":69},"Refund Policy","\u002Flegal\u002Frefund",{"label":71,"href":72},"Terms of Service","\u002Flegal\u002Fterms",{"links":74,"signIn":75,"contact":78,"cta":80},[],{"label":76,"href":77},"Manage account","url:portal.home",{"label":79,"href":62},"Get in touch",{"label":81,"href":82},"Download","url:routes.downloads",{},"data\u002Fshared\u002Fnavigation","XlSALC7vYCXHcmcXnjJViwIZKsqnQWF4bn4o9RrcSBE",{"id":87,"extension":5,"links":88,"meta":668,"stem":669,"__hash__":670},"urlSettings\u002Fdata\u002Fshared\u002Furls.yml",[89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157,161,165,169,173,177,181,185,189,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256,260,264,268,272,276,280,284,288,292,296,300,303,307,311,314,318,322,326,330,334,338,342,346,350,354,358,362,366,370,374,378,382,386,390,394,398,402,406,410,414,418,422,426,430,434,438,442,446,450,454,458,461,465,469,473,477,481,485,488,491,494,497,501,505,508,512,516,520,524,528,532,536,540,544,548,552,556,559,563,567,571,575,579,582,585,588,592,595,599,603,607,611,614,618,622,625,628,631,635,639,643,646,649,652,656,660,664],{"key":90,"label":91,"href":92},"downloads.desktop","Desktop download page","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdownload",{"key":94,"label":95,"href":96},"downloads.macOS.dmgArm64","macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg-arm64\u002Fdownload",{"key":98,"label":99,"href":100},"downloads.macOS.dmgIntel","macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg\u002Fdownload",{"key":102,"label":103,"href":104},"downloads.macOS.pkg","macOS PKG","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg\u002Fdownload",{"key":106,"label":107,"href":108},"downloads.macOS.universal","Desktop macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fmacos-universal\u002Fdownload",{"key":110,"label":111,"href":112},"downloads.macOS.pkgArm64","Desktop macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd-arm64\u002Fdownload",{"key":114,"label":115,"href":116},"downloads.macOS.pkgIntel","Desktop macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd\u002Fdownload",{"key":118,"label":119,"href":120},"downloads.windows.appinstaller","Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fpieces_for_x.appinstaller",{"key":122,"label":123,"href":124},"downloads.windows.exe","Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-exe\u002Fdownload",{"key":126,"label":127,"href":128},"downloads.windows.msix","Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-msix\u002Fdownload",{"key":130,"label":131,"href":132},"downloads.windows.suiteManager","Windows Suite Manager","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_suite_windows\u002Fappinstaller\u002Fdownload",{"key":134,"label":135,"href":136},"downloads.linux.flatpakRepo","Linux Flatpak repository","https:\u002F\u002Fbuilds.pieces.app\u002Fpieces-flatpak-repo\u002Fpieces-flatpak.flatpakrepo",{"key":138,"label":139,"href":140},"downloads.linux.snapDesktop","Linux Snap Desktop","https:\u002F\u002Fsnapcraft.io\u002Fpieces-for-developers",{"key":142,"label":143,"href":144},"downloads.linux.snapPiecesOS","Linux Snap PiecesOS","https:\u002F\u002Fsnapcraft.io\u002Fpieces-os",{"key":146,"label":147,"href":148},"downloads.linux.snap","Desktop Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fsnap\u002Fdownload",{"key":150,"label":151,"href":152},"downloads.piecesOS.macOS.dmgArm64","PiecesOS macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg-arm64\u002Fdownload",{"key":154,"label":155,"href":156},"downloads.piecesOS.macOS.dmgIntel","PiecesOS macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg\u002Fdownload",{"key":158,"label":159,"href":160},"downloads.piecesOS.macOS.universal","PiecesOS macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fmacos-universal\u002Fdownload",{"key":162,"label":163,"href":164},"downloads.piecesOS.macOS.pkgArm64","PiecesOS macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only-arm64\u002Fdownload",{"key":166,"label":167,"href":168},"downloads.piecesOS.macOS.pkgIntel","PiecesOS macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only\u002Fdownload",{"key":170,"label":171,"href":172},"downloads.piecesOS.windows.appinstaller","PiecesOS Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fos_server.appinstaller",{"key":174,"label":175,"href":176},"downloads.piecesOS.windows.exe","PiecesOS Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-exe\u002Fdownload",{"key":178,"label":179,"href":180},"downloads.piecesOS.windows.msix","PiecesOS Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-msix\u002Fdownload",{"key":182,"label":183,"href":184},"downloads.piecesOS.linux.snap","PiecesOS Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fsnap\u002Fdownload",{"key":186,"label":187,"href":188},"downloads.combined.macOS.appleSilicon","Combined macOS installer Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-arm64\u002Fdownload",{"key":190,"label":191,"href":104},"downloads.combined.macOS.intel","Combined macOS installer Intel",{"key":193,"label":194,"href":195},"downloads.guides.macOS","macOS installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fmacos-installation-guide",{"key":197,"label":198,"href":199},"downloads.guides.windows","Windows installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fwindows-installation-guide",{"key":201,"label":202,"href":203},"downloads.guides.linux","Linux installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide",{"key":205,"label":206,"href":207},"downloads.guides.linuxFlatpak","Linux Flatpak installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide\u002Fflatpak",{"key":209,"label":210,"href":211},"downloads.guides.linuxSnap","Linux Snap installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide\u002Fsnap",{"key":213,"label":214,"href":215},"downloads.guides.piecesOS","PiecesOS manual installation","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fmanual-installation",{"key":217,"label":218,"href":219},"extensions.chrome","Chrome extension","https:\u002F\u002Fchrome.google.com\u002Fwebstore\u002Fdetail\u002Fpieces-save-code-snippets\u002Figbgibhbfonhmjlechmeefimncpekepm",{"key":221,"label":222,"href":223},"extensions.firefox","Firefox add-on","https:\u002F\u002Faddons.mozilla.org\u002Fen-US\u002Ffirefox\u002Faddon\u002Fpieces-save-code-from-the-web\u002F",{"key":225,"label":226,"href":227},"extensions.edge","Edge add-on","https:\u002F\u002Fmicrosoftedge.microsoft.com\u002Faddons\u002Fdetail\u002Fpieces-save-code-snippet\u002Fhglfimcdgonaeeobjckfdabcldfidmim",{"key":229,"label":230,"href":231},"extensions.vscode","VS Code extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.pieces-vscode",{"key":233,"label":234,"href":235},"extensions.visualStudio","Visual Studio extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.PiecesVisualStudio",{"key":237,"label":238,"href":239},"extensions.jetbrains","JetBrains plugin","https:\u002F\u002Fplugins.jetbrains.com\u002Fplugin\u002F17328-pieces--save-search-share--reuse-code-snippets",{"key":241,"label":242,"href":243},"extensions.obsidian","Obsidian plugin","https:\u002F\u002Fobsidian.md\u002Fplugins?id=pieces-for-developers",{"key":245,"label":246,"href":247},"extensions.sublime","Sublime package","https:\u002F\u002Fpackagecontrol.io\u002Fpackages\u002FPieces",{"key":249,"label":250,"href":251},"extensions.neovim","Neovim plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neo_vim",{"key":253,"label":254,"href":255},"extensions.jupyterlab","JupyterLab plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fjupyterlab-pieces",{"key":257,"label":258,"href":259},"extensions.cli","Pieces CLI","https:\u002F\u002Fpypi.org\u002Fproject\u002Fpieces-cli\u002F",{"key":261,"label":262,"href":263},"docs.home","Documentation home","https:\u002F\u002Fdocs.pieces.app",{"key":265,"label":266,"href":267},"docs.getStarted","Get started docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces",{"key":269,"label":270,"href":271},"docs.api","API docs","https:\u002F\u002Fdocs.pieces.app\u002Fapi",{"key":273,"label":274,"href":275},"docs.desktop.overview","Desktop overview","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop",{"key":277,"label":278,"href":279},"docs.desktop.onboarding","Desktop onboarding","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fonboarding",{"key":281,"label":282,"href":283},"docs.desktop.timeline","Desktop timeline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Ftimeline",{"key":285,"label":286,"href":287},"docs.desktop.summaries","Desktop summaries docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fsingle-click-summaries",{"key":289,"label":290,"href":291},"docs.desktop.search","Desktop conversational search docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconversational-search",{"key":293,"label":294,"href":295},"docs.desktop.drive","Desktop drive docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdrive",{"key":297,"label":298,"href":299},"docs.desktop.account","Desktop account settings docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconfiguration\u002Faccount",{"key":301,"label":302,"href":92},"docs.desktop.download","Desktop download docs",{"key":304,"label":305,"href":306},"docs.piecesOS.overview","PiecesOS overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies",{"key":308,"label":309,"href":310},"docs.piecesOS.details","PiecesOS details docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os",{"key":312,"label":313,"href":215},"docs.piecesOS.install","PiecesOS install docs",{"key":315,"label":316,"href":317},"docs.piecesOS.quickMenu","PiecesOS quick menu docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fquick-menu",{"key":319,"label":320,"href":321},"docs.piecesOS.storage","On-device storage docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fon-device-storage",{"key":323,"label":324,"href":325},"docs.piecesOS.troubleshooting","PiecesOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Ftroubleshooting",{"key":327,"label":328,"href":329},"docs.mcp.overview","MCP overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp",{"key":331,"label":332,"href":333},"docs.mcp.cursor","MCP Cursor docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcursor",{"key":335,"label":336,"href":337},"docs.mcp.vscode","MCP VS Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fvs-code",{"key":339,"label":340,"href":341},"docs.mcp.claudeDesktop","MCP Claude Desktop docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-desktop",{"key":343,"label":344,"href":345},"docs.mcp.claudeCode","MCP Claude Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-code",{"key":347,"label":348,"href":349},"docs.mcp.claudeCowork","MCP Claude Cowork docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-cowork",{"key":351,"label":352,"href":353},"docs.mcp.githubCopilot","MCP GitHub Copilot docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgithub-copilot",{"key":355,"label":356,"href":357},"docs.mcp.goose","MCP Goose docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoose",{"key":359,"label":360,"href":361},"docs.mcp.windsurf","MCP Windsurf docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fwindsurf",{"key":363,"label":364,"href":365},"docs.mcp.zed","MCP Zed docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fzed",{"key":367,"label":368,"href":369},"docs.mcp.jetbrains","MCP JetBrains docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fjetbrains-ides",{"key":371,"label":372,"href":373},"docs.mcp.continueDev","MCP Continue docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcontinue-dev",{"key":375,"label":376,"href":377},"docs.mcp.cline","MCP Cline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcline",{"key":379,"label":380,"href":381},"docs.mcp.raycast","MCP Raycast docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fraycast",{"key":383,"label":384,"href":385},"docs.mcp.rovoDevCli","MCP Rovo Dev CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Frovo-dev-cli",{"key":387,"label":388,"href":389},"docs.mcp.openaiCodexCli","MCP OpenAI Codex CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenai-codex-cli",{"key":391,"label":392,"href":393},"docs.mcp.googleGeminiCli","MCP Google Gemini CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoogle-gemini-cli",{"key":395,"label":396,"href":397},"docs.mcp.amazonQ","MCP Amazon Q docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Famazon-q-developer",{"key":399,"label":400,"href":401},"docs.mcp.chatgptDev","MCP ChatGPT Developer Mode docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fchatgpt-developer-mode",{"key":403,"label":404,"href":405},"docs.mcp.openclaw","MCP OpenClaw docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenclaw",{"key":407,"label":408,"href":409},"docs.mcp.mcpRemote","MCP Remote docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fmcp-remote",{"key":411,"label":412,"href":413},"docs.mcp.ngrok","MCP ngrok docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fngrok-setup",{"key":415,"label":416,"href":417},"docs.troubleshooting.macOS","macOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fmacos",{"key":419,"label":420,"href":421},"docs.troubleshooting.windows","Windows troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fwindows",{"key":423,"label":424,"href":425},"docs.troubleshooting.linux","Linux troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Flinux",{"key":427,"label":428,"href":429},"docs.privacy","Privacy and security docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fprivacy-security-your-data",{"key":431,"label":432,"href":433},"docs.support","Support docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fsupport",{"key":435,"label":436,"href":437},"portal.home","Pieces portal","https:\u002F\u002Fportal.pieces.app",{"key":439,"label":440,"href":441},"site.home","Website home","https:\u002F\u002Fpieces.app",{"key":443,"label":444,"href":445},"site.about","About page","https:\u002F\u002Fpieces.app\u002Fabout",{"key":447,"label":448,"href":449},"site.features","Features page","https:\u002F\u002Fpieces.app\u002Ffeatures",{"key":451,"label":452,"href":453},"site.plugins","Plugins page","https:\u002F\u002Fpieces.app\u002Fplugins",{"key":455,"label":456,"href":457},"site.contact","Contact page","https:\u002F\u002Fpieces.app\u002Fcontact",{"key":459,"label":58,"href":460},"site.updates","https:\u002F\u002Fpieces.app\u002Fupdates",{"key":462,"label":463,"href":464},"site.news","News","https:\u002F\u002Fpieces.app\u002Fnews",{"key":466,"label":467,"href":468},"site.events","Community events","https:\u002F\u002Fpieces.app\u002Fcommunity\u002Fevents",{"key":470,"label":471,"href":472},"site.userStories","User stories","https:\u002F\u002Fpieces.app\u002Fuser-stories",{"key":474,"label":475,"href":476},"site.academy","Academy","https:\u002F\u002Fpieces.app\u002Flearn\u002Facademy",{"key":478,"label":479,"href":480},"site.support","Website support","https:\u002F\u002Fpieces.app\u002Fsupport",{"key":482,"label":483,"href":484},"site.standup","Standup","https:\u002F\u002Fpieces.app\u002Fstandup",{"key":486,"label":34,"href":487},"site.blog","https:\u002F\u002Fcode.pieces.app\u002Fblog",{"key":489,"label":43,"href":490},"social.discord","https:\u002F\u002Fdiscord.gg\u002Fgetpieces",{"key":492,"label":46,"href":493},"social.x","https:\u002F\u002Fx.com\u002Fgetpieces",{"key":495,"label":496,"href":493},"social.twitter","Twitter",{"key":498,"label":499,"href":500},"social.instagram","Instagram","https:\u002F\u002Fwww.instagram.com\u002Fgetpieces\u002F",{"key":502,"label":503,"href":504},"social.tiktok","TikTok","https:\u002F\u002Fwww.tiktok.com\u002F@getpieces",{"key":506,"label":49,"href":507},"social.linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fgetpieces\u002F",{"key":509,"label":510,"href":511},"social.youtube","YouTube","https:\u002F\u002Fyoutube.com\u002F@getpieces",{"key":513,"label":514,"href":515},"github.org","GitHub organization","https:\u002F\u002Fgithub.com\u002Fpieces-app",{"key":517,"label":518,"href":519},"github.support","GitHub support","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport",{"key":521,"label":522,"href":523},"github.issues","GitHub issues","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fissues",{"key":525,"label":526,"href":527},"github.discussions","GitHub discussions","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fdiscussions",{"key":529,"label":530,"href":531},"github.documentation","GitHub documentation","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fdocumentation",{"key":533,"label":534,"href":535},"github.opensource","GitHub open source","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fopensource",{"key":537,"label":538,"href":539},"github.sdks.python","Python SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-python",{"key":541,"label":542,"href":543},"github.sdks.typescript","TypeScript SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-typescript",{"key":545,"label":546,"href":547},"github.sdks.dart","Dart SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-dart",{"key":549,"label":550,"href":551},"github.sdks.kotlin","Kotlin SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-kotlin",{"key":553,"label":554,"href":555},"github.plugins.obsidian","Obsidian plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fobsidian-pieces",{"key":557,"label":558,"href":255},"github.plugins.jupyterlab","JupyterLab plugin repository",{"key":560,"label":561,"href":562},"github.plugins.sublime","Sublime plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_sublime",{"key":564,"label":565,"href":566},"github.plugins.neovim","Neovim plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neovim",{"key":568,"label":569,"href":570},"github.cliAgent","CLI agent repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fcli-agent",{"key":572,"label":573,"href":574},"github.mcpDart","MCP Dart repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fmcp_dart",{"key":576,"label":577,"href":578},"github.awesomePieces","Awesome Pieces repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fawesome-pieces",{"key":580,"label":581,"href":66},"legal.privacyPolicy","Privacy policy",{"key":583,"label":584,"href":69},"legal.refundPolicy","Refund policy",{"key":586,"label":587,"href":72},"legal.terms","Terms",{"key":589,"label":590,"href":591},"legal.security","Legal security","https:\u002F\u002Fpieces.app\u002Flegal\u002Fsecurity",{"key":593,"label":594,"href":511},"videos.youtubeChannel","YouTube channel",{"key":596,"label":597,"href":598},"videos.gettingStartedDesktop","Getting started desktop video","https:\u002F\u002Fyoutu.be\u002FdUr1lRM_TYk",{"key":600,"label":601,"href":602},"videos.snippetDiscoveryxR","Snippet discovery video","https:\u002F\u002Fyoutu.be\u002FG6vb1USw-30",{"key":604,"label":605,"href":606},"sales.bookACall","Book a sales call","https:\u002F\u002Fcalendar.app.google\u002FWVUDtUfNy5Vst3sH7",{"key":608,"label":609,"href":610},"sales.enterprise","Enterprise form","https:\u002F\u002Fgetpieces.typeform.com\u002Fto\u002FaVQFTvpE",{"key":612,"label":613,"href":527},"sales.feedback","Feedback discussions",{"key":615,"label":616,"href":617},"sales.earlyAccess","Early access form","https:\u002F\u002Fgetpieces.typeform.com\u002Fearlyaccess",{"key":619,"label":620,"href":621},"sales.supportEmail","Support email","mailto:support@pieces.app",{"key":623,"label":624,"href":19},"routes.home","Home route",{"key":626,"label":627,"href":56},"routes.about","About route",{"key":629,"label":630,"href":12},"routes.downloads","Downloads route",{"key":632,"label":633,"href":634},"routes.thanks","Post-install thanks route","\u002Finstall\u002Fthanks",{"key":636,"label":637,"href":638},"routes.pricing","Pricing route","\u002Fpricing",{"key":640,"label":641,"href":642},"cta.freeTrial","Start free trial CTA (Pieces Pro) — used by \u002Fcampaigns\u002F* landing pages","https:\u002F\u002Fcampaigns.pieces.app\u002F",{"key":644,"label":645,"href":22},"routes.enterprise","Enterprise route",{"key":647,"label":648,"href":62},"routes.contact","Contact route",{"key":650,"label":651,"href":59},"routes.updates","Updates route",{"key":653,"label":654,"href":655},"routes.migrationError","Migration error route","\u002Fmigration\u002Ferror",{"key":657,"label":658,"href":659},"routes.authenticated","Post-login authenticated route","\u002Fauth\u002Fsigned-in",{"key":661,"label":662,"href":663},"routes.signed-out","Signed out route","\u002Fauth\u002Fsigned-out",{"key":665,"label":666,"href":667},"routes.authentication-error","Authentication error route","\u002Fauth\u002Ferror",{},"data\u002Fshared\u002Furls","2AvfSWI6bZACH5Kr1ZS3txMLjteRjCjbDR_ul1uRZ9Q",{"id":672,"title":673,"author":674,"authorPhoto":675,"authorPhotoAlt":676,"authorSlug":677,"body":678,"buttonText":676,"buttonUrl":676,"category":963,"date":964,"description":965,"draft":966,"editorsPick":966,"extension":967,"featured":966,"image":968,"imageAlt":676,"meta":969,"navigation":32,"ogImage":676,"ogImageAlt":676,"path":970,"seo":971,"stem":972,"tags":676,"__hash__":973},"blog\u002Fblog\u002Fhow-to-extract-device-information-with-dart-ffi-on-windows.md","How to extract device information with Dart FFI on Windows","Rob Vrooman","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fhow-to-extract-device-information-with-dart-ffi-on-windows\u002Fauthor.jpg",null,"rob-vrooman",{"type":679,"value":680,"toc":950},"minimark",[681,685,689,693,696,699,703,708,719,729,733,742,746,749,755,758,763,769,772,776,782,802,806,812,821,834,837,843,846,850,856,859,862,868,871,877,880,886,889,892,896,902,911,915,921,924,933,939,943,947],[682,683,684],"p",{},"I’m Rob Vrooman, a software engineer here at Pieces for Developers. My main responsibilities are to develop and maintain plugins and integrations that interface with our core application. In my recent projects, I’ve been exploring the capabilities of Dart’s Foreign Function Interface (FFI) to interact with native Windows libraries. This journey has led me to delve into obtaining detailed device information using dxgi.dll. These tools have proven invaluable for accessing low-level system details and understanding development with Dart FFI.",[686,687],"h2",{"id":688},"",[686,690,692],{"id":691},"setting-the-stage","Setting the stage",[682,694,695],{},"The primary goal of this project is to gather device information so that the Pieces application can recommend the most powerful local Large Language Model (LLM) able to run effectively on the user's system. Much of our existing codebase is written in Dart, and by leveraging Dart’s FFI, I can call native C functions and interact with system libraries.",[686,697],{"id":698},"_1",[686,700,702],{"id":701},"extracting-device-information-with-dart-ffi-on-windows","Extracting device information with Dart FFI on Windows",[704,705,707],"h3",{"id":706},"setup","Setup",[682,709,710,711,718],{},"First, in your Dart project's pubspec.yaml file, be sure to include the latest 'ffi' package. If you will be working with Windows APIs, it is also recommended that you use the '",[712,713,717],"a",{"href":714,"rel":715},"https:\u002F\u002Fpub.dev\u002Fpackages\u002Fwin32",[716],"nofollow","win32","' package.",[720,721,726],"pre",{"className":722,"code":724,"language":725},[723],"language-text","    dependencies:\n        ffi: ^2.1.3\n        win32: ^5.7.1\n","text",[727,728,724],"code",{"__ignoreMap":688},[704,730,732],{"id":731},"using-dxgidll-for-device-information","Using dxgi.dll for device information",[682,734,735,736,741],{},"dxgi.dll (DirectX Graphics Infrastructure) provides a set of ",[712,737,740],{"href":738,"rel":739},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fwindows\u002Fwin32\u002Fapi\u002Fdxgi\u002F",[716],"APIs"," to enumerate graphics adapters and outputs. By interfacing with this DLL, I am able to retrieve detailed information about the video controllers installed on the system, such as the adapter description, memory size, and driver version.",[704,743,745],{"id":744},"implementation-details","Implementation details",[682,747,748],{},"Often, when I read blogs, I think to myself, \"Where is the code??\". To not bury the lead, here is what the dxgi.dll query ended up looking like:",[720,750,753],{"className":751,"code":752,"language":725},[723],"GPUInfo? _dxgiQuery(int deviceIndex) {\n    GPUInfo? gpuInfo = null;\n    using((Arena arena) {\n        final pFactory = arena\u003CPointer\u003Cwin32.COMObject>>();\n        int hresult = dxgi.CreateDXGIFactory1(dxgi.IID_IDXGIFactory4, pFactory.cast());\n        if (win32.SUCCEEDED(hresult)) {\n            final pAdapter = arena\u003CPointer\u003Cwin32.COMObject>>();\n            dxgi.IDXGIFactory1Object factory = dxgi.IDXGIFactory1Object(pFactory.cast());\n            hresult = factory.EnumAdapters1(deviceIndex, pAdapter.cast());\n            if (win32.SUCCEEDED(hresult)) {\n            dxgi.IDXGIAdapter1Object dxAdapter = dxgi.IDXGIAdapter1Object(pAdapter.cast());\n            final deviceDesc = arena\u003Cdxgi.DXGI_ADAPTER_DESC>();\n            hresult = dxAdapter.GetDesc(deviceDesc);\n            if (win32.SUCCEEDED(hresult)) {\n                List\u003Cint> charCodes = [];\n                \u002F\u002F Max 128 chars in Description\n                for (int i = 0; i \u003C 128; i++) {\n                int char = deviceDesc.ref.Description[i];\n                \u002F\u002F Null terminated string.\n                if (char == win32.NULL) break;\n                    charCodes.add(char);\n                }\n                gpuInfo = GPUInfo(\n                deviceIndex: deviceIndex,\n                type: String.fromCharCodes(charCodes),\n                dedicatedVRam: ByteInfo(value: deviceDesc.ref.DedicatedVideoMemory),\n                );\n            } else {\n                print('DeviceIndex: $deviceIndex FAILED: GetDesc');\n            }\n            } else {\n            print('DeviceIndex: $deviceIndex FAILED: EnumAdapters1');\n            }\n        } else {\n            print('DeviceIndex: $deviceIndex FAILED: CreateDXGIFactory1');\n        }\n    });\n    return gpuInfo;\n}\n",[727,754,752],{"__ignoreMap":688},[682,756,757],{},"Let's go into more detail about what exactly is going on here.",[759,760,762],"h4",{"id":761},"gpuinfo","GPUInfo",[720,764,767],{"className":765,"code":766,"language":725},[723],"GPUInfo? gpuInfo = null;\n",[727,768,766],{"__ignoreMap":688},[682,770,771],{},"A plain old Dart object meant to hold the extracted data.",[759,773,775],{"id":774},"arena","Arena",[720,777,780],{"className":778,"code":779,"language":725},[723],"using((Arena arena) {\n    \u002F\u002F ... scoped code\n }\n",[727,781,779],{"__ignoreMap":688},[682,783,784,785,789,790,795,796,801],{},"The ",[712,786,775],{"href":787,"rel":788},"https:\u002F\u002Fpub.dev\u002Fdocumentation\u002Fffi\u002Flatest\u002Fffi\u002FArena-class.html",[716]," class in dart FFI is basically a helper utility that ensures allocated memory is freed upon exiting the scope. Behind the scenes, it can use ",[712,791,794],{"href":792,"rel":793},"https:\u002F\u002Fpub.dev\u002Fdocumentation\u002Fffi\u002Flatest\u002Fffi\u002Fmalloc-constant.html",[716],"malloc"," or ",[712,797,800],{"href":798,"rel":799},"https:\u002F\u002Fpub.dev\u002Fdocumentation\u002Fffi\u002Flatest\u002Fffi\u002Fcalloc-constant.html",[716],"calloc"," to perform the allocation. The default allocator is calloc.",[759,803,805],{"id":804},"createdxgifactory1","CreateDXGIFactory1",[720,807,810],{"className":808,"code":809,"language":725},[723],"    final pFactory = arena\u003CPointer\u003Cwin32.COMObject>>();\n    int hresult = dxgi.CreateDXGIFactory1(dxgi.IID_IDXGIFactory4, pFactory.cast());\n    if (win32.SUCCEEDED(hresult)) {\n        \u002F\u002F ... proceed if success\n    }\n",[727,811,809],{"__ignoreMap":688},[682,813,814,815,820],{},"First, we allocate the necessary memory for a pointer to a ",[712,816,819],{"href":817,"rel":818},"https:\u002F\u002Fpub.dev\u002Fdocumentation\u002Fwin32\u002Flatest\u002Fwin32\u002FCOMObject-class.html",[716],"win32 COMObject"," as required by CreateDXGIFactory1.",[682,822,784,823,827,828,833],{},[712,824,805],{"href":825,"rel":826},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fwindows\u002Fwin32\u002Fapi\u002Fdxgi\u002Fnf-dxgi-createdxgifactory1",[716]," function creates a factory that can be used to generate other DXGI objects. In our case, we're looking to create an IDXGIFactory object to be able to iterate the available graphics adapters with the ",[712,829,832],{"href":830,"rel":831},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fwindows\u002Fwin32\u002Fapi\u002Fdxgi\u002Fnf-dxgi-idxgifactory-enumadapters",[716],"EnumAdapters"," function.",[682,835,836],{},"Setting up dart functions to call these functions through FFI looks something like this:",[720,838,841],{"className":839,"code":840,"language":725},[723],"\u002F\u002F Load the DXGI library\nfinal dxgi = DynamicLibrary.open('dxgi.dll');\nfinal CreateDXGIFactory1 = \n         \u002F\u002F lookup the native function symbol.\n         \u002F\u002F Be sure that the generic for the lookupFunction call matches the signature of the native function.\n    dxgi.lookupFunction\u003Cwin32.HRESULT Function(REFIID, Pointer\u003CPointer\u003CVoid>>),\n        \u002F\u002F Convert the native function into a compatible dart function.\n        \u002F\u002F 'CreateDXGIFactory1' matches the function name of the native function.\n        int Function(REFIID, Pointer\u003CPointer\u003CVoid>>)>('CreateDXGIFactory1');\n",[727,842,840],{"__ignoreMap":688},[682,844,845],{},"With the factory function call setup, we are able to enumerate the adapters:",[759,847,849],{"id":848},"enumerating-adapters","Enumerating adapters",[720,851,854],{"className":852,"code":853,"language":725},[723],"final pAdapter = arena\u003CPointer\u003Cwin32.COMObject>>();\ndxgi.IDXGIFactory1Object factory = dxgi.IDXGIFactory1Object(pFactory.cast());\nhresult = factory.EnumAdapters1(deviceIndex, pAdapter.cast());\nif (win32.SUCCEEDED(hresult)) {\n     \u002F\u002F ... proceed if success\n}\n",[727,855,853],{"__ignoreMap":688},[682,857,858],{},"Again, we start by allocating the required memory buffer. Next, we create our IDXGIFactory1Object from the Void Pointer received from the original create factory call.",[682,860,861],{},"Where'd that come from? Here's where it gets a bit more complex: to call functions that are part of an object and class layout, we need to understand which memory location to point to:",[720,863,866],{"className":864,"code":865,"language":725},[723],"class IDXGIFactory1Object extends win32.IUnknown {\n    IDXGIFactory1Object(super.ptr);\n    int EnumAdapters1(int Adapter, Pointer\u003CPointer\u003CVoid>> ppAdapter) =>\n        \u002F\u002F Use the VTable layout to obtain a pointer to the native function\n        (ptr.ref.vtable + 12)\n                .cast\u003CPointer\u003CNativeFunction\u003Cwin32.HRESULT Function(Pointer, Uint32, Pointer\u003CPointer\u003CVoid>>)>>>()\n                .value\n                \u002F\u002F Translate the native function to a dart function\n                .asFunction\u003Cint Function(Pointer, int, Pointer\u003CPointer\u003CVoid>>)>()\n            \u002F\u002F Call the function\n            (ptr.ref.lpVtbl, Adapter, ppAdapter);\n    }\n",[727,867,865],{"__ignoreMap":688},[682,869,870],{},"VTables and the like deserve a blog unto themselves, but for this case, I can simply say that the layout can be dumped by your compiler. In my case, I used the command:",[720,872,875],{"className":873,"code":874,"language":725},[723],"cl \u002Fd1reportAllClassLayout \u003CfileName>.cpp\n",[727,876,874],{"__ignoreMap":688},[682,878,879],{},"For a clang class layout dump of:",[720,881,884],{"className":882,"code":883,"language":725},[723],"\u002F\u002FIDXGIFactory1::$vftable@:\n\u002F\u002F | &IDXGIFactory1_meta\n\u002F\u002F |  0\n\u002F\u002F  0 | &IUnknown::QueryInterface\n\u002F\u002F  1 | &IUnknown::AddRef\n\u002F\u002F  2 | &IUnknown::Release\n\u002F\u002F  3 | &IDXGIObject::SetPrivateData\n\u002F\u002F  4 | &IDXGIObject::SetPrivateDataInterface\n\u002F\u002F  5 | &IDXGIObject::GetPrivateData\n\u002F\u002F  6 | &IDXGIObject::GetParent\n\u002F\u002F  7 | &IDXGIFactory::EnumAdapters\n\u002F\u002F  8 | &IDXGIFactory::MakeWindowAssociation\n\u002F\u002F  9 | &IDXGIFactory::GetWindowAssociation\n\u002F\u002F 10 | &IDXGIFactory::CreateSwapChain\n\u002F\u002F 11 | &IDXGIFactory::CreateSoftwareAdapter\n\u002F\u002F 12 | &IDXGIFactory1::EnumAdapters1\n\u002F\u002F 13 | &IDXGIFactory1::IsCurrent\n",[727,885,883],{"__ignoreMap":688},[682,887,888],{},"Notice how the EnumAdapters1 function has an offset number of '12', the same as used in the code above. The Dart FFI library handles offsets with memory size calculations, so you can use this number directly.",[682,890,891],{},"Now, starting from 0 and incrementing the device index until failure, we can retrieve information about the adapters.",[759,893,895],{"id":894},"adapter-descriptions","Adapter descriptions",[720,897,900],{"className":898,"code":899,"language":725},[723],"dxgi.IDXGIAdapter1Object dxAdapter = dxgi.IDXGIAdapter1Object(pAdapter.cast());\nfinal deviceDesc = arena\u003Cdxgi.DXGI_ADAPTER_DESC>();\nhresult = dxAdapter.GetDesc(deviceDesc);\nif (win32.SUCCEEDED(hresult)) {\n   \u002F\u002F ... proceed if success\n}\n",[727,901,899],{"__ignoreMap":688},[682,903,904,905,910],{},"What's new here? Now that we have a Void Pointer that's meant to be an ",[712,906,909],{"href":907,"rel":908},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fwindows\u002Fwin32\u002Fapi\u002Fdxgi\u002Fnn-dxgi-idxgiadapter1",[716],"IDXGIAdapter1",", we create a new object from that pointer. Since the pattern of how this is accomplished has already been discussed, I will leave it out for brevity.",[759,912,914],{"id":913},"gpuinfo-1","GPUInfo!",[720,916,919],{"className":917,"code":918,"language":725},[723],"List\u003Cint> charCodes = [];\n\u002F\u002F Max 128 chars in Description\nfor (int i = 0; i \u003C 128; i++) {\n    int char = deviceDesc.ref.Description[i];\n    \u002F\u002F Null terminated string.\n    if (char == win32.NULL) break;\n    charCodes.add(char);\n}\ngpuInfo = GPUInfo(\n    deviceIndex: deviceIndex,\n    type: String.fromCharCodes(charCodes),\n    dedicatedVRam: ByteInfo(value: deviceDesc.ref.DedicatedVideoMemory),\n);\n",[727,920,918],{"__ignoreMap":688},[682,922,923],{},"We made it! We have the data!",[682,925,926,927,932],{},"There's one more important piece here to go over. How is ",[712,928,931],{"href":929,"rel":930},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fwindows\u002Fwin32\u002Fapi\u002Fdxgi\u002Fns-dxgi-dxgi_adapter_desc",[716],"DXGI_ADAPTER_DESC"," defined in our Dart code? This structure must match the expected memory layout as shown in the documentation:",[720,934,937],{"className":935,"code":936,"language":725},[723],"base class DXGI_ADAPTER_DESC extends Struct {\n    @Array\u003Cwin32.WCHAR>(128)\n    external Array\u003Cwin32.WCHAR> Description;\n    @Uint32()\n    external int VendorId;\n    @Uint32()\n    external int DeviceId;\n    @Uint32()\n    external int SubSysId;\n    @Uint32()\n    external int Revision;\n    @Uint64()\n    external int DedicatedVideoMemory;\n    @Uint64()\n    external int DedicatedSystemMemory;\n    @Uint64()\n    external int SharedSystemMemory;\n    external LUID AdapterLuid;\n}\nbase class LUID extends Struct {\n    @Uint32()\n    external int LowPart;\n    @Int32()\n    external int HighPart;\n}\n",[727,938,936],{"__ignoreMap":688},[940,941],"h1",{"id":942},"_2",[686,944,946],{"id":945},"conclusion","Conclusion",[682,948,949],{},"This project has been an incredible learning experience, providing deep insights into both Dart’s capabilities and the intricacies of Windows system programming. By combining Dart with FFI and leveraging dxgi.dll, I was able to unlock powerful functionalities to obtain device information, which in turn lets us provide the most well-optimized generative AI experience for our users within Pieces.",{"title":688,"searchDepth":951,"depth":951,"links":952},2,[953,954,955,956,962],{"id":688,"depth":951,"text":688},{"id":691,"depth":951,"text":692},{"id":698,"depth":951,"text":688},{"id":701,"depth":951,"text":702,"children":957},[958,960,961],{"id":706,"depth":959,"text":707},3,{"id":731,"depth":959,"text":732},{"id":744,"depth":959,"text":745},{"id":945,"depth":951,"text":946},"Software Development","2024-11-21T00:00:00.000Z","Learn how to extract device information on Windows using Dart FFI. Follow code examples to effectively access and utilize device data in your Dart applications.",false,"md","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fhow-to-extract-device-information-with-dart-ffi-on-windows\u002Fhero.png",{},"\u002Fblog\u002Fhow-to-extract-device-information-with-dart-ffi-on-windows",{"title":673,"description":965},"blog\u002Fhow-to-extract-device-information-with-dart-ffi-on-windows","Akkr6DlVW8dMa7RD3OzniUKLpHkc-QysT5tVoSbOBNA",{"id":975,"title":674,"body":976,"description":980,"draft":966,"extension":967,"meta":983,"navigation":32,"path":984,"photo":985,"photoAlt":676,"seo":986,"stem":987,"__hash__":988},"authors\u002Fauthors\u002Frob-vrooman.md",{"type":679,"value":977,"toc":981},[978],[682,979,980],{},"Robert started taking an interest in software development in high school after a friend had developed a Galaga clone written in Java. Eventually this passion led him to study Software Engineering at the Rochester Institute of Technology. At Pieces, he is responsible for creating the Visual Studio integration. Outside of work, you can find him playing frisbee with his two border collies or hopping on Discord for a host of different gaming sessions.",{"title":688,"searchDepth":951,"depth":951,"links":982},[],{},"\u002Fauthors\u002Frob-vrooman","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fauthors\u002Frob-vrooman.png",{"title":674,"description":980},"authors\u002Frob-vrooman","gr5EQx-whMX-44rqz9Z5s4ZjmtKeLwMyl2rTSoFf5S8",{"left":990,"top":990,"width":991,"height":991,"rotate":990,"vFlip":966,"hFlip":966,"body":992},0,24,"\u003Cpath fill=\"currentColor\" d=\"m7.825 13l4.9 4.9q.3.3.288.7t-.313.7q-.3.275-.7.288t-.7-.288l-6.6-6.6q-.15-.15-.213-.325T4.426 12t.063-.375t.212-.325l6.6-6.6q.275-.275.688-.275t.712.275q.3.3.3.713t-.3.712L7.825 11H19q.425 0 .713.288T20 12t-.288.713T19 13z\"\u002F>"]