<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Axiorema Engineering Blog</title>
        <link>https://blog.axiorema.com/engineering/</link>
        <description>Practical stories and insights we learned during product development.</description>
        <lastBuildDate>Thu, 16 Apr 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[We improved OneDrive folder automount]]></title>
            <link>https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/</link>
            <guid>https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/</guid>
            <pubDate>Thu, 16 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[The “Configure team site libraries to sync automatically” OneDrive policy can be intuitive and easy to set up.]]></description>
            <content:encoded><![CDATA[<p>A lesser-known feature of Microsoft OneDrive is the ability to <strong>automatically mount</strong>
shared file libraries from your organization.</p>
<p>Imagine handing a laptop to a new employee with all company files available out of
the box and continuously synced — a pretty cool feat, right?</p>
<p><em>Sure, if only configuring the policies wasn’t an administrative nightmare.</em></p>
<p>We were developing <a href="https://www.axiorema.com/visualdrive-server/" data-no-ext="true">VisualDrive Server</a>,
a self-hosted server for OneDrive. And we tried to make the automount experience a
bit more intuitive.</p>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15 16" style="max-width:25rem"><path fill="currentColor" d="M14.929 15.99H.079l-.03-.035V6.12L.048.044C.048.022.066 0 .09 0h14.812c.03 0 .05.017.05.044L14.95 7.17v8.792zM14.88.077H.121V15.92h14.76z"></path><path fill="currentColor" d="M.973 7.019a.2.2 0 0 1-.086.01c-.01 0-.02-.025-.019-.034s.015-.024.027-.028a3.6 3.6 0 0 1 .63-.152c.16-.02.315-.018.476-.012l.458-.006c.19-.003.6-.08.768-.164l.126-.063a.9.9 0 0 0 .32-.266c.078-.1.149-.2.211-.31l.142-.254a.1.1 0 0 1 .03-.02c.007-.004.029.014.027.024-.021.127-.21.406-.304.54a1.04 1.04 0 0 1-.384.344l-.173.087c-.177.088-.59.145-.808.159l-.412.003-.198-.003a2.4 2.4 0 0 0-.706.106zM4.803 3.909c-.048.112-.088.221-.146.324-.014.006-.042-.003-.046-.014-.005-.013 0-.032.007-.048l.177-.425.199-.417c.053-.113.084-.224.106-.347.045-.253.072-.506.043-.763-.012-.104-.054-.264-.008-.313.006-.006.032.002.033.012l.026.186c.046.333.027.619-.034.947a1.5 1.5 0 0 1-.133.374l-.166.348zM7.451 7.784c-.11 0-.297.02-.397.028-.15.013-.602.024-.602.024-.022 0-.05.005-.057-.029-.003-.015.02-.037.033-.038l.238-.01s.589-.049.785-.048c.195 0 .777.051.777.051l.165.01c.01 0 .023.024.021.035a.06.06 0 0 1-.023.033l-.366-.02c-.143-.011-.448-.035-.574-.036ZM6.972 3.07l-.232.002-.253.004c-.022 0-.044-.01-.047-.03s.015-.042.04-.043l.217-.007.013-.174.045-.385c-.1.01-.266.013-.257-.047.003-.018.024-.03.044-.029l.096.007.38-.008c.014 0 .034.018.035.03s-.017.04-.031.04l-.202.004-.032.316-.029.248.197.002c.015 0 .036.011.042.024.005.013-.01.047-.026.047M9.063 5.024c-.01.115-.033.412-.088.414-.012 0-.034-.023-.032-.037l.015-.102.033-.252.045-.405c.01-.09-.01-.129.02-.142.062-.028.046.107.038.192zM8.48 8.813c-.014-.005-.018-.043-.014-.057l.084-.31.06-.251.03-.236c.001-.01.018-.03.027-.03.07-.01.012.28-.016.393l-.05.196-.063.246c-.007.027-.02.062-.059.049M7.032 4.117c-.102.044-.198-.041-.236-.164-.003-.012.009-.037.017-.043.01-.007.04 0 .043.012.01.052.03.093.071.121a.087.087 0 0 0 .117-.017c.07-.083.117-.203.046-.256-.05-.037-.15.052-.24-.035-.042-.04-.05-.098-.029-.154a.23.23 0 0 1 .106-.115c.065-.038.149-.037.2.021.008.009.009.035.002.044s-.033.012-.042.004c-.043-.037-.099-.03-.145.003-.042.03-.078.08-.053.133.037.078.143-.014.232.037.093.052.09.195.015.308a.25.25 0 0 1-.104.101M6.68 4.044c0 .017-.02.036-.03.038-.013.001-.04-.02-.039-.034l.009-.206-.004-.332c0-.012.016-.032.027-.033.014-.001.035.015.036.032l.01.183zM10.796 3.098c-.002.01-.022.026-.033.024-.01-.002-.024-.016-.033-.028l.021-.375v-.144c0-.01.007-.032.016-.035a.1.1 0 0 1 .047.006l.002.21.301-.019.004-.242c0-.012.026-.027.037-.024.017.004.028.021.028.041l-.004.296c-.001.087.001.166.018.254.003.011-.002.036-.01.044s-.034.01-.043.005c-.031-.02-.041-.22-.031-.313l-.305.03zM11.64 3.106c-.088-.013-.186-.112-.148-.16.005-.007.032-.01.038-.003l.07.073c.04.042.11.028.141-.02.037-.06.06-.142.034-.21-.015-.035-.07-.025-.096-.013q-.076.036-.138-.008c-.09-.066-.054-.233.043-.288a.2.2 0 0 1 .236.026c.005.009-.006.034-.015.04-.04.026-.09-.05-.174-.01-.07.032-.091.142-.05.176.021.016.056.015.08.002.067-.035.155-.018.18.057.034.1.004.21-.062.289a.14.14 0 0 1-.138.049Z"></path><path fill="currentColor" d="M10.527 3.081c0 .018-.018.037-.032.036-.022 0-.038-.018-.036-.042l.024-.373.008-.207-.19.01c-.012 0-.031-.015-.037-.024-.034-.058.112-.05.195-.056l.175-.013c.08-.006.187-.005.187.041 0 .026-.02.041-.046.039l-.07-.008-.148.007c.01.204-.04.375-.03.59M11.381 3.038c0 .016-.02.037-.033.036-.012 0-.03-.023-.03-.038l.004-.207c.002-.108.008-.209-.001-.317-.002-.018.014-.04.027-.04.026 0 .04.016.04.04l-.003.317z"></path><circle cx="5.977" cy="5.261" r="0.052" fill="currentColor"></circle><path fill="currentColor" d="M9.028 11.443c-.034-.096-.073-.285-.021-.265.008.003.022.017.024.025.011.086.027.17.057.25.014.037.046.072.09.068.083-.009.098-.181.112-.29.012-.086-.029-.134.002-.142.051-.012.05.113.04.202-.009.077-.015.155-.053.223a.12.12 0 0 1-.16.05c-.047-.023-.074-.071-.091-.12M8.694 11.772c-.006-.01-.002-.031.005-.036.031-.019.056.052.093.037.111-.043.096-.18.07-.3l-.035-.165-.026-.03c-.005-.006.003-.029.012-.034.017-.01.045.01.05.032l.062.248a.4.4 0 0 1 0 .158.2.2 0 0 1-.07.118c-.053.045-.126.035-.162-.028M9.56 11.614c.048.066.1.005.134.006.006 0 .018.013.015.018l-.017.02c-.042.052-.115.053-.162.001a.3.3 0 0 1-.054-.092c-.029-.111-.006-.294.083-.359.01-.008.042 0 .046.011q.003.023-.02.04c-.034.024-.043.065-.054.105-.026.085-.025.178.028.25M8.594 12.004l.076-.01c.018-.003.033-.044.027-.062a.1.1 0 0 0-.048-.054l-.024-.014c-.007-.004.001-.03.01-.03.038-.004.084.025.101.056.021.037.028.083.002.12-.025.035-.078.043-.117.031l-.022-.007c-.006-.002-.006-.021-.005-.03Z"></path><path fill="currentColor" d="m9.206 13.79.014-.648-.172-.043-.671-.126-.484-.073c.26.088.526.124.798.155l.391.067c.04.007.09.03.085.078-.006.06-.045.114-.064.17l-.12.355-.178.463-.142.357-.079.207a.07.07 0 0 1-.03.03c-.012.005-.037-.008-.043-.019-.007-.013-.003-.034.003-.05l.09-.227.206-.52.13-.355c-.2.156-.45.207-.69.229l.05.028c.01.006.003.047-.01.049l-.06.008.007.162.043.411c.012.112.028.217.07.321l.07.176c.016.04.074.062.108.088l.064.048c.026.02.023.046.002.077.03.024.053.06.047.1-.01.082-.127.121-.221.089a.1.1 0 0 1-.05-.05c-.008-.021-.005-.062.01-.078l.046-.05a.7.7 0 0 0-.254-.04l-.29.01c-.113.003-.223-.003-.335.019.01.037.02.082 0 .112a.15.15 0 0 1-.185.045.1.1 0 0 1-.05-.054c-.012-.04.025-.13.066-.15.044-.02.046-.053.067-.088l.125-.214c.058-.099.09-.205.128-.314l.09-.257c.044-.125.072-.252.102-.384a.2.2 0 0 1-.115-.024l-.232-.003-.201-.001c-.109 0-.212.01-.319-.018a.24.24 0 0 1-.07-.109l-.093-.312a7 7 0 0 1-.129-.645l-.08-.54c-.113.003-.174.019-.195-.08l-.035-.16-.022-.134a.3.3 0 0 1 .135-.104l-.022-.15c-.001-.012.023-.028.035-.026.016.003.027.017.03.033l.014.085.115-.04.01-.193a.8.8 0 0 1 .115-.361c.043-.06.14-.06.202-.025a.4.4 0 0 1 .159.204 1 1 0 0 1 .065.206l.098.61c.015.093-.009.187-.025.28a.35.35 0 0 1-.197.268c-.1.043-.244-.164-.287-.283l-.06-.169-.072.024.062.381c.024.212.057.413.106.621.042.174.08.34.144.505.007.018.026.049.043.052.088.017.17.015.257.011l.185-.007q.02-.001.001-.007l-.07-.013a.6.6 0 0 1-.263-.102.25.25 0 0 1-.096-.146c-.017-.104.045-.193.135-.243.18-.1.504-.156.717-.16l.236-.003c.19-.003.377.018.554.082.117.042.2.119.259.231l.097-.232-.442-.079c-.174-.02-.342-.039-.512-.08a3 3 0 0 1-.419-.128l-.099-.107a.2.2 0 0 1-.04-.07l-.144-.465c-.09-.285-.092-.478-.086-.771a3 3 0 0 1 .058-.475l.013-.094c.046-.058.02-.11.085-.113a1.17 1.17 0 0 1-.237-.784l.027-.236a.8.8 0 0 1 .32-.526.8.8 0 0 1 .41-.116c.117-.004.22.038.329.067a.88.88 0 0 1 .5.34c.073.103.12.211.12.34v.181a1.572 1.572 0 0 1-.264.788.7.7 0 0 1-.26.233.55.55 0 0 1-.364.055 1.03 1.03 0 0 1-.55-.3c-.01.027-.027.075-.016.098l.057.12.2.377.248.439.056.087.246.064c.175.046.347.08.53.084.053 0 .102 0 .155.013.045.011.09.008.136.01.046.001.086.05.128.066.088.02.142-.026.164-.02.033.01.084.014.116.004l.004-.168-.015-.01-.209-.016c-.019-.001-.055-.006-.064-.021-.03-.054-.007-.108.013-.158l.025-.066.278-.013.28.016.308.025.182.01.3.002.16-.008.37-.014.142-.014.23-.01.205-.007h.506l.138-.008.166-.015c.012 0 .039-.02.045-.011l.025.037c-.004.08.002.151.012.229l-.026.221-.002.168-.004.45-.013.459-.006.214-.014.45-.03.483-.011.197.022.215.012.157.01.183c.002.029-.018.058-.049.06-.034.003-.067-.008-.102-.009l-.164-.005-.262.005-.198.017c-.083.008-.161.005-.244-.003l-.206.003-.19-.01-.229.01-.261-.016-.308.009a3 3 0 0 0-.601.012l-.112.014-.186.02c-.01.001-.033-.005-.04-.012s-.011-.028-.01-.039l.012-.254.023-.4.008-.246.008-.303.002-.42.006-.328.01-.114.005-.143.025-.288.013-.241-.469.069a.5.5 0 0 1-.139-.004c-.06-.007-.067-.14-.01-.21l.139.014c-.01-.034-.04-.07-.071-.072l-.233-.008-.232-.004-.403-.04-.192-.014c-.018-.001-.04-.019-.048-.037l-.073-.181-.262-.67-.072-.18c-.002-.01-.013-.004-.016.007-.048.25-.061.685.004.913l.16.56c.052.184.156.149.302.173l.77.13.468.086c.044.008.085.02.121.046.023.017.024.05.022.077l-.014.222-.004.1-.007.308.023.35.011.191.022.346c.003.048.03.14-.026.132a.1.1 0 0 1-.038-.024l-.029-.422zm-.893-2.708c.067-.016.12-.056.174-.09.101-.062.197-.22.253-.334.113-.227.158-.446.152-.7a.6.6 0 0 0-.118-.358.8.8 0 0 0-.44-.294l-.226-.062a.67.67 0 0 0-.453.093c-.23.149-.321.448-.323.715l-.001.11c-.001.124.03.238.08.35a1.1 1.1 0 0 0 .196.327l.111.095c.06.05.127.08.2.11.124.048.26.071.395.038m-1.17 1.506a.38.38 0 0 0 .134-.244c.021-.128.018-.25-.005-.378l-.044-.257c-.022-.122-.04-.242-.086-.357-.05-.124-.124-.25-.255-.203-.096.141-.109.316-.114.487a1.4 1.4 0 0 0 .016.25c.036.236.101.563.288.71.022.018.046.009.067-.008m1.226-.441-.352-.088-.073-.126-.19-.332-.09-.15.21.535.072.17.589.06h.153zm-1.599 0-.039-.203-.027-.193a.3.3 0 0 0-.095.043l.085.371.076-.019Zm2.578-.313-.034.105c.08.01.15.018.227.018l.364.003.276.002.215.005.372.026.236.013.21.005.335-.032c.155-.023.303-.01.46-.014l.568-.014-.007-.143-.638.018h-.305l-.249.009-.088.01-.181.012-.302.008-.255.01-.251-.005-.12-.005-.34-.025-.276-.012zm-2.718.348-.079-.34-.08.054.066.288zm5.857 2.992c.009 0 .024.002.026-.004s.005-.024.004-.031l-.01-.199-.012-.139c-.023-.126-.015-.242-.007-.368l.025-.433.014-.301.003-.222.013-.35.005-.18.005-.213v-.293c.001-.142.01-.276.021-.42l-.146.002-.505.006c-.094 0-.183-.005-.276.005-.178.021-.351.057-.532.047l-.253-.015-.426-.03-.239-.006-.292-.002-.292-.006-.01.317-.011.355-.027.294-.006.203a2.6 2.6 0 0 0-.017.39l-.006.213.001.308-.008.159-.005.198-.026.51-.006.257.254-.035c.216-.03.424-.035.642-.01l.153-.008c.115-.006.223-.004.338.01.12.015.236-.023.418 0h.237c.104.006.2.009.303 0l.235-.02h.214zm-3.113-2.848c-.031-.041-.07-.028-.096-.026.005.016.01.026.005.028l-.029.014zm-.427.182.192-.01.4-.06-.001-.069-.308.046-.212.023-.072-.004zm-.635 1.248c.186-.009.525-.098.613-.267a.4.4 0 0 0-.103-.146.55.55 0 0 0-.258-.106l-.185-.03-.317-.003-.15.002-.26.025a1.3 1.3 0 0 0-.41.122c-.052.029-.095.08-.095.141 0 .226.506.246.717.259l.238.014zm-.317 1.201c.121.01.228.025.351.058l-.068-.188a1.4 1.4 0 0 1-.075-.369l-.044-.533-.2-.015c-.034.178-.093.336-.147.504l-.029.091c-.06.186-.128.36-.231.535a.83.83 0 0 1 .443-.083m.218.155.203.018c-.043-.035-.093-.046-.146-.059-.237-.058-.493-.083-.705.06l.33-.012zm-.73.168c.005-.01-.002-.037-.01-.043-.035-.003-.087.014-.094.05.025.029.085.022.103-.007m.956.046c.09.03.145-.016.13-.03l-.03-.031-.09.031c-.006.003-.017.028-.01.03Z"></path><path fill="currentColor" d="M10.893 11.675c.024.001.02.07-.007.07l-.308-.007-.143.007c-.017.001-.04.002-.05-.008-.007-.01-.01-.037-.003-.047s.029-.017.045-.018l.222-.008.003-.178.007-.196a.3.3 0 0 0-.047-.005l-.005.142c-.085.002-.158.001-.237.024a.15.15 0 0 1-.076.003c-.022-.035-.003-.07 0-.105l.029-.373.06-.7.047-.729.014-.144.019-.255c0-.01-.008-.037-.002-.045.007-.009.029-.015.042-.014l.13.012h.128c.013 0 .038.008.043.019.006.014 0 .04-.002.056l-.025.122.279.366a1 1 0 0 0-.066.192l-.037.174-.039.373-.017.22-.01.157-.007.17v.11l.007.172a.1.1 0 0 1-.01.048c-.006.01-.033.022-.047.02l-.096-.012q-.016.19-.003.382zm-.362-.424.008-.281.012-.222.01-.182.026-.318.05-.435.045-.336.043-.294-.198-.016-.015.21-.03.43-.044.577-.023.225-.041.566-.019.199.176-.021zm.285-.032-.005-.087v-.17l.04-.644.034-.31.053-.22.04-.112-.217-.283-.025.176-.066.528-.024.242-.024.332-.01.18-.008.358zM8.89 2.865l-.03.209c-.001.01-.019.025-.028.028-.058.012-.141-.197-.184-.289l-.119-.256-.004.225-.022.283c-.002.02-.017.039-.032.039-.016 0-.04-.021-.037-.037.022-.134.028-.26.025-.396a.7.7 0 0 1 .02-.217c.028-.017.065.008.082.035.056.087.097.178.136.274.031.076.06.143.109.214l.024-.203.011-.278a.04.04 0 0 1 .022-.042c.013-.006.039.009.04.025l.004.089zM8.291 2.807l-.29.05-.057.187c-.006.02-.019.037-.036.036s-.036-.028-.031-.044l.042-.135.093-.32c.018-.063.089-.192.141-.196.065-.005.115.096.14.174l.046.143.047.333c.003.018-.015.04-.027.042-.024.003-.039-.012-.041-.035zm-.01-.07-.066-.21-.051-.072a.2.2 0 0 0-.047.05 1.1 1.1 0 0 0-.099.276zM7.546 2.961c.064.062.177.04.252-.018.01-.01.04-.006.05.007.007.01.005.034-.007.045a.3.3 0 0 1-.14.067c-.08.02-.157 0-.214-.062a.18.18 0 0 1-.05-.148.7.7 0 0 1 .194-.427c.073-.076.174-.076.246-.004.014.014.03.029.036.042s-.004.053-.019.056c-.036.009-.064-.073-.121-.08a.11.11 0 0 0-.092.033.63.63 0 0 0-.175.364.14.14 0 0 0 .04.125ZM9.377 2.971c-.003.081.026.134-.013.146-.013.004-.045-.007-.048-.022a.3.3 0 0 1-.004-.108c.014-.147.021-.286.01-.44l-.139.028c-.02.004-.043-.007-.048-.027-.003-.014.013-.042.032-.046q.215-.045.437-.03c.012 0 .03.026.03.038s-.023.03-.036.03l-.205.003zM9.123 2.306c.016.102-.072.207-.099.158-.022-.04.043-.06.038-.17 0-.01.023-.023.032-.02s.027.02.03.032M9.56 3.047c-.023-.003-.053-.038-.054-.06-.002-.037.03-.055.056-.056.035 0 .06.02.062.053 0 .03-.02.069-.063.063"></path><circle cx="14.368" cy="7.402" r="0.059" fill="currentColor"></circle><path fill="currentColor" d="M5.792.753a.37.37 0 0 1 .106.152c.044.14.047.323-.075.413a.23.23 0 0 1-.201.03.18.18 0 0 1-.125-.134c-.036.037-.07.078-.115.107-.057.036-.142.017-.188-.029a.33.33 0 0 1-.1-.154c-.029-.135.053-.29.14-.401.03-.039.074-.074.129-.055.026.009.051.056.053.082.001.008-.018.025-.027.023-.008-.002-.02-.01-.031-.016l-.03-.017c-.008-.004-.026.012-.033.02-.12.14-.216.33-.068.46.027.023.056.042.093.038.085-.007.084-.114.169-.087-.007-.17.024-.347.153-.47l.105.001c.015 0 .032.024.045.037m.038.163a.2.2 0 0 0-.116-.12c-.039-.011-.066.007-.084.036a.53.53 0 0 0-.08.255c-.003.047-.005.102.021.144.033.051.103.071.159.056.143-.039.153-.232.1-.371M9.3 1.363l-.032.02c-.008.004-.022-.02-.025-.03l-.002-.304.012-.227c.001-.022-.02-.05-.004-.076.008-.011.038-.01.055-.006.108-.077.246-.084.328.012q.056.065.036.149-.017.069-.101.112c.063.03.113.07.136.136a.15.15 0 0 1-.058.179.34.34 0 0 1-.278.038c-.018-.005-.053-.01-.067-.003m.138-.303c-.033-.001-.054-.012-.05-.046.007-.055.066-.018.158-.063.048-.023.077-.083.05-.131a.15.15 0 0 0-.17-.067.3.3 0 0 0-.107.068l-.011.252v.213l.11.02c.07.013.201-.011.221-.084.022-.078-.072-.16-.201-.162ZM6.791 1.301c-.005.01-.035.017-.043.01s-.02-.028-.019-.04l.032-.404.015-.178c.006-.015.053-.019.06-.006.058.126.113.246.185.363l.08.112.02-.41c0-.03.025-.07.048-.083.009-.004.03.007.035.016.013.028-.013.041-.016.124l-.008.212-.015.282c0 .014-.036.026-.048.023a.06.06 0 0 1-.04-.039c-.028-.072-.071-.132-.111-.198L6.83.865zM6.39.817c0-.015-.021-.037-.038-.04l-.104.151c-.01.014-.028.03-.041.03a.1.1 0 0 1-.048-.022l-.11-.13-.012.275-.002.243c0 .012-.023.026-.032.024-.01-.003-.03-.02-.03-.031L5.97 1.12l.01-.23L5.98.707c0-.01.011-.034.022-.036s.034.007.04.015l.159.18.114-.164C6.33.681 6.353.666 6.38.67c.067.01.085.13.076.221l-.024.277c-.007.075.023.125-.013.135-.032.01-.056-.047-.053-.087l.02-.285zM10.35 1.347c-.021.005-.05-.007-.06-.017-.015-.014 0-.052.001-.068l.014-.447c0-.02-.02-.054.006-.074.014-.01.048-.007.067-.011.077-.018.154-.03.228.008.059.031.115.09.13.158.036.153-.039.348-.178.4zm.167-.114c.11-.023.194-.202.148-.336a.18.18 0 0 0-.214-.11l-.082.022-.013.457zM8.754 1.286l-.083.063c-.042.032-.097.03-.143.01a.14.14 0 0 1-.092-.131.6.6 0 0 1 .184-.46c.035-.033.107-.03.14.002.018.019.032.036.056.047a.195.195 0 0 1 .084.288 1 1 0 0 1-.146.181m.098-.236A.12.12 0 0 0 8.84.927a.14.14 0 0 0-.095-.056L8.69.839l-.062.019a.55.55 0 0 0-.13.348c0 .052.036.107.091.1.098-.013.213-.158.263-.256M10.095 1.246l.102.01c.014.002.025.03.022.041-.003.015-.026.034-.044.032a1 1 0 0 0-.238-.003l-.118.014c-.013.001-.037-.009-.043-.018s-.01-.037-.008-.05l.012-.188.007-.098.002-.171c0-.018-.016-.061.007-.072l.14-.017.244.007c.01.012.018.036.013.046-.006.013-.033.026-.05.026L9.857.803l-.004.202c.094-.016.21-.024.191.037-.002.01-.018.027-.028.027h-.168l-.013.198c.095-.012.173-.03.26-.02ZM7.641 1.015c-.073 0-.13.05-.141-.004-.003-.016.012-.04.029-.043l.105-.024c.035-.008.071.014.073.05a.4.4 0 0 1-.094.278.13.13 0 0 1-.13.047c-.135-.026-.217-.218-.214-.35.003-.153.089-.328.247-.319.07.004.14.054.162.12-.05.073-.102-.093-.217-.044-.058.024-.088.081-.108.137a.34.34 0 0 0 .023.28c.027.054.07.11.14.11.07-.001.117-.137.125-.238M4.39.97c-.024.158-.199.379-.32.313a.2.2 0 0 1-.105-.195.6.6 0 0 1 .132-.365A.08.08 0 0 1 4.15.7c.014 0 .032.018.046.033l.079.005A.22.22 0 0 1 4.39.97ZM4.324.898C4.312.834 4.26.808 4.2.803 4.177.8 4.143.794 4.121.802a.5.5 0 0 0-.093.305c0 .048.04.13.098.118.112-.025.217-.21.197-.327M4.765.729a.1.1 0 0 1 .059.081l-.015.176a.7.7 0 0 1-.083.27c-.04.074-.118.096-.192.06a.22.22 0 0 1-.118-.188c-.007-.123.009-.242.032-.362.004-.02.011-.038.026-.04.017-.004.043.02.04.04a1.2 1.2 0 0 0-.032.366c.005.05.025.096.07.12.043.025.096.015.121-.033a.8.8 0 0 0 .082-.421c-.001-.022-.033-.044.01-.07ZM3.67 1.074a.12.12 0 0 0-.021-.065l-.14-.226C3.497.761 3.48.726 3.485.705c.002-.01.032-.019.04-.014.01.006.021.02.03.033l.156.261c.08-.093.147-.187.2-.29.005-.012.009-.026.015-.031.008-.006.033-.006.04.001.03.032-.025.125-.067.183l-.101.138c-.02.027-.056.067-.056.101l.002.224c0 .02-.02.038-.037.039-.023.001-.033-.023-.034-.048l-.003-.229ZM8.179 1.32l.022-.29.005-.257-.136.048c-.02.007-.046.002-.052-.016-.007-.022.004-.043.025-.051a.8.8 0 0 1 .236-.065l.22-.016c.01 0 .032.01.036.02.005.01.001.033-.005.045-.006.01-.028.007-.044.006a1 1 0 0 0-.211.016c.005.113-.004.215-.012.323l-.02.228c0 .02-.009.036-.027.038-.012.001-.039-.015-.038-.03M10.96 1.145c-.017-.102-.085-.128-.011-.192l.143-.124c.022-.02.028-.053.02-.08-.017-.06-.134-.071-.228.007-.012.009-.034.016-.044.01-.012-.005-.022-.035-.013-.046.07-.094.242-.12.32-.043.032.033.058.099.034.145-.04.079-.114.13-.183.185l.027.121c.002.012-.016.032-.026.035-.011.003-.038-.006-.04-.018ZM6.584 1.298c-.016 0-.034-.04-.033-.058l.01-.191.006-.308c0-.023.057-.027.06-.006.014.108.001.214-.002.323l-.007.196c0 .015-.014.044-.034.043ZM10.976 1.341c-.028-.007-.034-.036-.028-.058.008-.027.034-.036.066-.03.029.006.038.035.03.06q-.014.039-.068.028M2.578 1.33a.48.48 0 0 0-.317-.286c0 .09.003.176.01.267 0 .025.002.062-.036.066-.016-.012-.028-.048-.029-.074l-.01-.264c-.003-.102 0-.202-.013-.305-.001-.012-.01-.038-.002-.046.008-.007.027-.015.041-.02.095-.037.197-.054.293-.013.054.024.082.078.097.133.021.083-.011.17-.09.204l-.1.045a.8.8 0 0 1 .133.116c.066.07.118.177.067.196-.012.004-.04-.007-.045-.02M2.524.907c.039-.038.03-.093.01-.136-.05-.1-.175-.083-.284-.046L2.26.99c.1-.013.2-.019.265-.082M2.02 1.064l-.276.022-.043.246c-.003.016-.028.032-.042.03-.012-.003-.028-.024-.025-.039l.055-.28c.02-.099.106-.402.14-.432.031-.027.122.068.16.15.064.14.137.399.144.542 0 .012-.023.035-.034.034s-.028-.02-.034-.035a1.5 1.5 0 0 0-.045-.238Zm-.015-.07a1 1 0 0 0-.106-.26C1.88.72 1.857.714 1.84.728l-.085.29zM2.798 1.27a.2.2 0 0 0 .054.005q.144-.02.287-.01c.01.008.016.035.011.047-.004.01-.025.023-.04.022a2 2 0 0 0-.31.016c-.015.002-.043-.006-.052-.016s-.012-.037-.013-.055c-.003-.097-.01-.19-.005-.285a.9.9 0 0 0-.018-.261c-.005-.019.016-.04.033-.038.146.008.242-.043.314-.017.027.009.038.033.03.052-.013.03-.035.015-.06.018l-.24.026c.007.062.01.133.007.199l.14-.017q.026.02.031.042c.002.012-.022.029-.035.03l-.14.019zM8.981 4.104a.3.3 0 0 1-.1-.227l.003-.125c-.078.127-.208.133-.357.113l.005.212c0 .012-.015.031-.025.036-.011.006-.046-.007-.046-.021v-.5c0-.02-.019-.059.001-.077a.3.3 0 0 1 .322-.048c.093.04.132.123.123.23a.6.6 0 0 1 .112-.177q.044-.037.088-.013c.12-.005.203.117.213.24.012.152-.027.333-.164.389a.16.16 0 0 1-.175-.032Zm-.143-.448a.14.14 0 0 0-.078-.125.23.23 0 0 0-.232.018l.003.247c.141.02.304-.002.307-.14Zm.291.418c.12-.06.16-.265.107-.393-.025-.06-.085-.108-.152-.099-.033.005-.054.04-.07.064-.08.12-.087.295-.003.402a.09.09 0 0 0 .118.026ZM7.955 3.621l-.013.284-.018.187c-.002.018-.018.037-.032.039-.024.001-.04-.02-.038-.044l.026-.198.008-.34c0-.02-.001-.042.015-.052.05-.03.164.165.208.25l.13-.233c.008-.016.044-.028.06-.025.073.013.068.198.06.305-.007.098-.006.188.012.285.003.014-.004.043-.015.046s-.032-.004-.046-.013a1 1 0 0 1-.013-.317c.003-.076.007-.147-.008-.226a1.3 1.3 0 0 0-.145.294c-.002.007-.013.022-.02.023s-.023-.006-.033-.012a1 1 0 0 0-.138-.253ZM10.794 4.098q0 .037-.022.047c-.013.005-.044-.012-.043-.027l.004-.114.01-.478c0-.012.033-.023.044-.02a.1.1 0 0 1 .04.032c.099.138.176.282.256.434l.015-.415c0-.017-.003-.04.006-.047.011-.01.037-.01.05-.002.01.006.014.028.013.044l-.01.242-.013.279a.05.05 0 0 1-.035.045c-.018.007-.04-.008-.05-.03a3 3 0 0 0-.244-.44zM9.75 4.109c-.063-.11-.174-.26-.294-.282l.007.26c0 .024-.005.043-.03.048-.014.003-.037-.018-.038-.038l-.004-.208-.006-.28-.02-.048c-.004-.012.02-.038.032-.043l.056-.018c.114-.038.24-.021.318.073.041.118-.07.212-.195.234.098.063.209.194.242.288.004.012-.018.033-.03.033-.01 0-.033-.01-.038-.02m-.044-.502a.193.193 0 0 0-.254-.033l.002.186c.112-.004.274-.047.252-.153M10.319 3.911l-.047.172c-.005.02-.019.036-.038.034s-.036-.026-.031-.045l.038-.165.059-.186.055-.174c.009-.03.05-.067.081-.046a1 1 0 0 1 .126.221l.12.334c.006.015-.017.036-.03.038-.013.001-.035-.011-.04-.025l-.064-.191zm.204-.103-.114-.214-.074.245zM11.476 4.108c-.001.01-.03.021-.04.018s-.027-.023-.027-.038l.003-.215.003-.323-.17.027c-.015.003-.037-.011-.04-.026s.011-.038.03-.041a2.6 2.6 0 0 1 .48-.046c.022 0 .04.023.038.042s-.023.035-.045.034a1.3 1.3 0 0 0-.225.006l-.005.28zM10.055 4.1a.036.036 0 0 1-.035.033c-.014-.001-.034-.023-.034-.04l.01-.361-.006-.175-.166.015c-.012 0-.03-.016-.031-.027-.003-.013.01-.041.024-.042l.163-.013.282-.021c.016-.001.034.015.036.03.002.01-.013.036-.026.037l-.214.018v.271zM7.721 4.092c.001.011-.023.027-.033.024s-.033-.02-.034-.032c-.008-.097.001-.185.007-.281l.017-.27q.002-.03.026-.038c.011-.003.039.015.038.03l-.02.293c-.005.093-.012.175 0 .274M11.679 4.091c-.026.007-.05-.023-.057-.04-.011-.025-.001-.05.018-.073.016-.02.046-.03.067-.02.024.01.04.037.032.067-.005.025-.03.059-.06.066M4.453 4.676l-.043.254c-.02.115-.055.223-.092.333-.004.013-.023.03-.035.032-.012 0-.04-.014-.046-.025l-.086-.166c-.03.063-.053.129-.092.185-.02.03-.065.002-.078-.027a4 4 0 0 1-.082-.501l-.019-.087c-.002-.01.006-.03.015-.036.01-.006.04 0 .043.014l.024.093c.022.153.035.298.073.457l.077-.2c.007-.018.02-.033.038-.033.014 0 .034.017.038.032.017.068.04.127.079.188.046-.122.07-.241.092-.368l.03-.176c.001-.012.033-.019.043-.013s.023.028.02.044M5.318 5.05l-.246.02-.04.188c-.003.012-.024.027-.036.028s-.033-.024-.03-.036L5 5.077q.033-.17.107-.329a.17.17 0 0 1 .076-.083c.061-.03.127.096.154.185.04.131.064.261.08.398.003.014-.017.037-.028.04-.015.003-.038-.014-.04-.03zm-.013-.068-.04-.147-.056-.105c-.024.021-.042.038-.05.061l-.078.213zM4.572 5.231c0 .018-.009.038-.02.042-.01.004-.04-.012-.04-.025l.002-.304.013-.276c0-.011.025-.023.033-.02.01.004.027.023.026.034l-.01.241.264-.026.003-.21c0-.022.007-.044.025-.048.015-.003.043.02.043.039l-.01.406.013.174c.001.019-.011.042-.028.043s-.033-.013-.042-.031c-.009-.103-.01-.2-.004-.307l-.27.026zM5.61 5.263c-.001.018-.016.04-.028.042-.014.002-.041-.021-.04-.038l.022-.31c.005-.078-.007-.155-.013-.234l-.149.008c-.02.001-.039-.012-.041-.03-.003-.022.012-.04.038-.04l.393-.022c.021-.002.044.021.044.038 0 .022-.02.036-.044.037l-.175.003c.015.126.01.238.003.359zM5.948 4.952c.01-.073.066-.046.148-.094.08-.052.06-.2-.043-.203-.083-.017-.095.095-.161.093-.06-.1.132-.199.221-.15.182.078.097.349-.087.36-.006.2-.126.2-.078-.006ZM9.345 5.798c.025-.024.066-.015.069.018-.038.146-.072.279-.102.432l-.014.05c-.14.347-.21-.271-.252-.376-.007-.011-.032-.074-.026-.082.013-.012.053-.057.063-.038.08.144.066.366.138.507M11.923 5.765c.027-.014.081.01.113.017l.056.03.005.003a.2.2 0 0 1 .035.03c.12.098.065.33-.015.429-.06.076-.137.138-.228.117-.108-.04-.137-.163-.146-.266a1 1 0 0 1 .005-.103c.007-.02.01-.073.023-.084.04-.075.078-.152.152-.173Zm.018.06c-.092.063-.149.222-.127.333.003.058.066.204.156.155.002 0 .022-.015.023-.015.179-.113.206-.447-.052-.473M6.754 6.064c-.025.158-.2.379-.321.313a.2.2 0 0 1-.104-.194.6.6 0 0 1 .131-.365.08.08 0 0 1 .053-.025c.014 0 .033.018.046.034l.079.005a.22.22 0 0 1 .116.232Zm-.068-.072c-.011-.064-.062-.09-.122-.095-.023-.002-.058-.009-.079 0a.5.5 0 0 0-.094.304c0 .048.04.131.098.118.112-.024.217-.21.197-.327M6.866 6.359c-.005.01-.035.017-.043.01s-.02-.028-.02-.04l.033-.404.015-.178c.006-.015.052-.019.06-.006.058.126.113.246.184.363l.08.112.02-.41c.001-.03.025-.07.048-.083.01-.004.031.007.035.016.013.028-.013.04-.016.124l-.008.212-.015.282c0 .014-.035.026-.048.023a.06.06 0 0 1-.04-.039c-.028-.072-.07-.132-.111-.198l-.135-.22zM7.425 6.306a.2.2 0 0 0 .054.004q.143-.018.287-.01c.01.009.016.036.011.048-.005.01-.025.023-.04.022a2 2 0 0 0-.31.016c-.015.002-.043-.006-.052-.016s-.012-.037-.013-.056c-.003-.096-.01-.188-.005-.284a.9.9 0 0 0-.018-.262c-.005-.018.016-.038.033-.038.146.008.242-.042.314-.017.027.01.038.034.03.052-.013.031-.035.016-.06.018l-.24.027c.007.062.01.133.007.199l.14-.017c.016.013.029.027.03.041.003.013-.021.03-.034.031l-.14.019zM7.89 6.368c-.02.005-.05-.007-.06-.017-.014-.014.001-.052.002-.068l.013-.447c.001-.02-.02-.054.007-.074.013-.01.048-.007.066-.011.077-.018.154-.03.229.008.058.031.114.09.13.158.036.153-.04.348-.179.4zm.167-.114c.11-.023.194-.202.149-.336a.18.18 0 0 0-.214-.111l-.083.023-.012.457zM8.722 6.352c-.063-.11-.174-.26-.294-.282l.007.26c0 .024-.005.043-.03.048-.014.003-.037-.018-.038-.038l-.004-.208-.006-.28-.02-.048c-.004-.012.02-.038.032-.043l.056-.018c.114-.038.24-.021.318.073.041.118-.07.213-.195.234.098.063.209.194.242.289.004.011-.018.032-.03.032-.01 0-.033-.01-.038-.019m-.044-.502a.193.193 0 0 0-.254-.033l.002.186c.112-.004.274-.047.252-.153M8.926 6.36c.001.01-.023.026-.033.023s-.033-.02-.034-.032c-.008-.097.001-.185.007-.28l.017-.27q.002-.032.026-.039c.011-.003.039.015.038.03l-.02.293c-.005.093-.012.175 0 .274ZM9.815 6.305l.101.01c.014.001.025.03.022.041-.002.015-.026.034-.044.031a1 1 0 0 0-.238-.002l-.118.013c-.012.002-.036-.008-.043-.018s-.009-.036-.008-.05l.013-.188.006-.098.003-.17c0-.019-.016-.062.006-.073l.14-.017.244.007c.011.012.018.036.013.047-.006.013-.033.026-.05.026l-.286-.002-.004.201c.095-.016.21-.024.192.038-.003.01-.019.027-.029.027h-.167l-.014.198c.095-.013.173-.03.26-.021ZM10.367 6.152l-.047.171c-.006.02-.019.037-.038.034s-.036-.026-.031-.045l.037-.165.06-.185.054-.175c.01-.029.051-.067.082-.046a1 1 0 0 1 .126.221l.12.335c.005.014-.018.036-.031.037-.012.001-.034-.011-.039-.024l-.064-.192zm.204-.104-.114-.214-.074.246zM11.122 5.773a.1.1 0 0 1 .059.081l-.014.176a.7.7 0 0 1-.084.27c-.04.073-.118.096-.192.06a.22.22 0 0 1-.118-.188c-.007-.123.01-.242.033-.362.003-.02.01-.038.026-.041.017-.004.043.02.039.04a1.2 1.2 0 0 0-.031.366c.004.052.025.097.069.122.043.024.096.014.122-.034a.8.8 0 0 0 .082-.421c-.002-.022-.033-.044.009-.07ZM11.476 6.363c-.001.011-.03.022-.04.02-.01-.004-.027-.025-.027-.04l.003-.214.003-.323-.17.027c-.015.003-.037-.011-.04-.026s.011-.038.03-.042a2.6 2.6 0 0 1 .48-.045c.022 0 .04.023.038.042s-.023.035-.045.034a1.3 1.3 0 0 0-.225.006l-.005.28zM13.119 6.3l-.083.063c-.042.032-.097.03-.143.01a.14.14 0 0 1-.092-.132.6.6 0 0 1 .184-.459c.035-.034.107-.03.14.001.018.019.032.037.056.048a.195.195 0 0 1 .084.287 1 1 0 0 1-.146.182Zm.099-.237a.12.12 0 0 0-.013-.123.14.14 0 0 0-.095-.056l-.055-.032-.061.019a.55.55 0 0 0-.13.348c-.001.052.035.107.09.1.098-.013.213-.158.264-.256M14.26 6.16l-.03.209c-.002.01-.02.025-.03.027-.057.013-.14-.196-.183-.288l-.119-.256-.004.225-.022.283c-.002.02-.017.039-.032.038-.016 0-.04-.02-.037-.036.022-.134.028-.26.025-.396a.7.7 0 0 1 .02-.217c.028-.017.065.008.082.035.056.086.097.178.136.274.031.075.06.143.109.214l.024-.203.011-.278a.04.04 0 0 1 .021-.042c.014-.006.04.008.04.025l.005.088zM14.548 6.25c-.003.08.027.133-.012.145-.013.004-.045-.007-.049-.022a.3.3 0 0 1-.003-.108c.013-.147.02-.285.01-.44l-.14.028c-.02.004-.042-.007-.047-.027-.004-.013.012-.042.032-.046.145-.03.287-.04.436-.03.013 0 .031.026.03.038s-.022.031-.035.031l-.205.002zM12.684 5.887c0-.015-.021-.037-.038-.04l-.105.151c-.009.014-.028.03-.04.03a.1.1 0 0 1-.048-.022l-.11-.13-.012.275-.003.243c0 .012-.022.026-.032.023s-.03-.02-.03-.03l-.001-.196.01-.23-.002-.184c0-.01.012-.034.023-.036s.034.007.04.015l.159.18.114-.164c.015-.022.038-.036.065-.032.067.01.085.13.076.221l-.025.277c-.006.074.024.124-.012.135-.032.01-.056-.047-.054-.087l.02-.285zM13.696 5.791a.1.1 0 0 1 .06.082l-.015.176a.7.7 0 0 1-.084.269c-.04.074-.117.097-.192.061a.22.22 0 0 1-.117-.189c-.007-.122.009-.241.032-.362.004-.02.01-.037.026-.04.017-.004.043.02.04.04a1.2 1.2 0 0 0-.032.366c.005.051.025.096.07.121.043.024.096.015.121-.034a.8.8 0 0 0 .082-.42c-.001-.022-.033-.045.01-.07ZM6.714 7.257l-.03.21c-.001.01-.019.025-.028.027-.059.013-.142-.196-.184-.288l-.12-.256-.003.225-.023.283c-.001.019-.016.038-.032.038-.015 0-.038-.02-.036-.037.022-.133.028-.26.025-.395a.7.7 0 0 1 .02-.217c.028-.017.065.007.082.034.056.087.097.179.136.275.031.075.06.143.108.214l.024-.204.012-.277a.04.04 0 0 1 .021-.042c.013-.007.04.008.04.025l.005.088zM7.398 7.447a.2.2 0 0 0 .054.005q.143-.02.287-.01c.011.008.017.035.012.047-.005.01-.026.023-.04.022a2 2 0 0 0-.31.016c-.016.002-.044-.005-.052-.016-.01-.01-.013-.037-.013-.055-.004-.097-.01-.19-.005-.285a.9.9 0 0 0-.019-.261c-.004-.019.017-.04.033-.038.147.008.243-.042.315-.017.027.01.038.033.03.052-.013.03-.036.015-.06.018l-.24.026c.007.063.01.134.006.199l.14-.017q.027.02.032.042c.001.012-.023.029-.035.03l-.141.019zM7.145 7.426l.101.01c.014.001.025.029.022.04-.002.016-.026.034-.044.032a1 1 0 0 0-.238-.002l-.118.013c-.012.001-.036-.009-.043-.018s-.01-.037-.008-.05l.013-.188.006-.098.002-.17c0-.02-.016-.062.007-.073l.14-.017.244.007c.011.012.018.036.013.047-.006.013-.033.025-.05.025l-.286-.002-.004.202c.094-.016.21-.024.192.037-.003.01-.019.028-.03.028h-.167l-.013.197c.095-.012.173-.03.26-.02ZM7.853 7.505c-.02.004-.05-.007-.06-.018-.014-.014.001-.051.002-.068l.014-.446c0-.021-.02-.055.006-.075.013-.01.048-.006.067-.01.077-.019.154-.031.228.007.059.031.115.09.13.159.036.153-.04.347-.178.4zm.167-.115c.11-.023.195-.201.15-.336a.18.18 0 0 0-.215-.11l-.083.023-.012.456zM8.537 7.552c-.101.044-.198-.041-.236-.164-.003-.012.009-.037.018-.043.01-.007.04 0 .042.012.011.052.03.093.072.121a.087.087 0 0 0 .116-.017c.07-.083.118-.203.046-.256-.05-.037-.15.052-.24-.035-.042-.04-.049-.098-.028-.154a.23.23 0 0 1 .105-.115c.065-.038.15-.037.2.021.008.009.01.035.003.044s-.034.012-.043.004c-.043-.037-.098-.03-.144.003-.042.03-.078.08-.054.132.037.08.143-.013.232.037.094.053.09.196.016.31a.25.25 0 0 1-.105.1ZM9.16 7.466c0 .011-.024.027-.033.024-.011-.003-.034-.02-.034-.032-.008-.097.001-.185.007-.281l.016-.27q.003-.03.026-.038c.012-.003.04.015.038.03l-.019.293c-.006.093-.013.175-.001.274ZM9.356 7.01l-.013.284-.019.186c-.001.018-.017.038-.03.039-.025.002-.042-.02-.039-.044l.026-.197.008-.34c0-.02-.001-.043.014-.053.05-.03.165.165.208.25l.13-.233c.009-.016.045-.028.061-.025.073.013.068.198.06.306-.007.097-.006.187.012.285.003.013-.004.042-.015.045-.011.004-.032-.003-.046-.013a1 1 0 0 1-.013-.317c.003-.076.007-.147-.009-.225a1.3 1.3 0 0 0-.144.293c-.002.007-.013.022-.02.023-.009.001-.023-.006-.033-.012a1 1 0 0 0-.138-.253ZM10.266 7.13c-.078.127-.208.133-.357.113l.005.212c0 .012-.015.031-.025.036-.011.006-.046-.007-.046-.021v-.5c0-.02-.019-.059.001-.077a.3.3 0 0 1 .322-.048c.093.04.132.123.123.23zm-.046-.096a.14.14 0 0 0-.078-.125.23.23 0 0 0-.232.018l.003.247c.141.02.304-.002.307-.14M10.703 7.448c-.063-.11-.175-.259-.294-.282l.007.26c0 .024-.005.043-.03.048-.014.003-.038-.018-.038-.038l-.004-.208-.006-.28-.02-.048c-.004-.012.019-.038.032-.043l.056-.018c.114-.038.24-.021.317.074.042.117-.07.212-.195.233.099.063.21.194.242.289.004.011-.018.032-.028.032s-.034-.01-.04-.019m-.044-.502a.193.193 0 0 0-.254-.033l.002.186c.112-.004.274-.047.252-.153M11.666 6.908c.025-.025.066-.016.069.018-.038.146-.072.279-.102.431l-.014.051c-.14.346-.21-.272-.252-.376-.007-.011-.032-.074-.026-.082.013-.012.053-.057.063-.039.08.145.066.367.138.508M12.142 7.387l.101.01c.014.002.025.03.022.041-.002.015-.026.034-.044.032a1 1 0 0 0-.238-.003l-.118.014c-.013.001-.037-.009-.043-.018s-.01-.037-.008-.05l.013-.188.006-.098.002-.171c0-.018-.016-.061.007-.072l.14-.017.244.007c.011.012.018.036.013.046-.006.013-.033.026-.05.026l-.286-.002-.004.202c.095-.016.21-.024.192.037-.003.01-.019.027-.03.027h-.167l-.013.198c.095-.012.173-.03.26-.02ZM12.39 7l-.013.284-.019.186c-.002.019-.018.038-.031.04-.024.001-.041-.02-.038-.044l.025-.198.008-.34c0-.02 0-.042.015-.052.05-.031.164.164.208.25l.13-.233c.009-.016.045-.028.06-.025.074.013.069.198.06.305-.007.098-.005.188.013.285.002.014-.005.043-.016.046s-.032-.004-.045-.013a1 1 0 0 1-.013-.317c.003-.077.006-.148-.009-.226a1.3 1.3 0 0 0-.144.294c-.003.007-.014.022-.02.023q-.016-.002-.034-.012A1 1 0 0 0 12.39 7ZM12.964 7.448a.2.2 0 0 0 .054.004q.143-.018.287-.01c.01.009.017.036.011.048-.004.01-.025.023-.04.022a2 2 0 0 0-.31.016c-.015.002-.043-.006-.052-.016s-.012-.037-.013-.056c-.003-.096-.01-.188-.005-.284a.9.9 0 0 0-.018-.262c-.005-.018.017-.038.033-.037.146.008.242-.043.314-.017.027.009.038.033.03.051-.013.031-.035.016-.06.019l-.24.026c.008.062.01.133.007.199l.14-.017c.016.013.03.027.031.042.002.012-.022.029-.035.03l-.14.019zM13.41 7.49c-.006.01-.036.018-.044.01s-.02-.028-.019-.04l.032-.403.015-.179c.006-.014.052-.018.06-.005.058.125.113.245.185.363l.08.111.02-.409c0-.03.025-.071.048-.083.009-.004.03.007.035.015.013.029-.013.042-.016.124l-.008.213-.015.282c0 .014-.036.026-.048.023a.06.06 0 0 1-.04-.039c-.028-.073-.071-.132-.111-.198l-.136-.22zM14.136 7.467c-.001.01-.03.022-.04.019-.01-.004-.027-.024-.027-.039l.003-.215.003-.323-.17.028c-.015.002-.037-.012-.04-.027s.011-.038.03-.041a2.6 2.6 0 0 1 .48-.045c.022 0 .04.022.038.041s-.023.035-.045.034a1.3 1.3 0 0 0-.225.006l-.005.28zM11.006 6.867c.027-.013.082.011.114.017l.056.03.004.004a.2.2 0 0 1 .035.03c.121.098.065.33-.015.428-.06.077-.137.138-.228.118-.107-.04-.137-.163-.146-.266a1 1 0 0 1 .005-.104c.008-.02.01-.072.024-.083.04-.076.077-.152.151-.174Zm.018.061c-.092.063-.148.222-.127.333.003.058.066.204.156.155.003 0 .022-.015.023-.015.18-.114.206-.447-.052-.473"></path></svg>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="err-what-automount">Err… what? Automount?<a href="https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/#err-what-automount" class="hash-link" aria-label="Direct link to Err… what? Automount?" title="Direct link to Err… what? Automount?" translate="no">​</a></h2>
<p>Automount is a shorthand for the <em>“Configure team site libraries to sync automatically”</em>
OneDrive policy.</p>
<p>The OneDrive client app has many policies that can be configured by the administrator.
They change different aspects of the app behavior. For example, you can configure <a href="https://www.axiorema.com/docs/visualdrive-server/latest/admin/installation/gpo-silent-deployment/" data-no-ext="true">silent sign-in</a>,
customize bandwidth usage,
<a href="https://www.axiorema.com/docs/visualdrive-server/latest/admin/installation/gpo-known-folder-move/" data-no-ext="true">back up standard folders</a>,
and automatically mount folders.</p>
<img src="https://blog.axiorema.com/assets/images/explorer-automount-light-de551096177a1a017ddf1aae7a5fabb6.webp" class="Image_Jtan Border_PJCd themedComponent_mlkZ themedComponent--light_NVdE" width="1037" height="576" style="width:70%"><img src="https://blog.axiorema.com/assets/images/explorer-automount-dark-3e93b463cbe7d7657ef847cbe0f49695.webp" class="Image_Jtan Border_PJCd themedComponent_mlkZ themedComponent--dark_xIcU" width="1037" height="576" style="width:70%">
<p>An automount policy allows predefined shared locations to automatically sync to your
device. These locations appear as folders in the File Explorer. Different users
can have different automount policies assigned to them.</p>
<div class="theme-admonition theme-admonition-tip admonition_Gfwi alert alert--success"><div class="admonitionContent_UjKb"><p>Automounted folder works like a centrally advertised network share, but with better
structure and all <strong>OneDrive features</strong>: automatic sync, simplified sharing and access
management, versioning, retention, search, and on-demand content fetching.</p></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="why-is-cloud-automount-hard-to-configure">Why is cloud automount hard to configure?<a href="https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/#why-is-cloud-automount-hard-to-configure" class="hash-link" aria-label="Direct link to Why is cloud automount hard to configure?" title="Direct link to Why is cloud automount hard to configure?" translate="no">​</a></h2>
<p>In the cloud, the server environment and the OneDrive policy distribution environment
<strong>have no knowledge</strong> of each other.</p>
<p>As a result, no administrative tool can provide a convenient editor for the automount
configuration — one that stays up-to-date with the remote state, and where you can pick
what to mount.</p>
<!-- -->
<p>This results in a rather unintuitive configuration experience with several problems:</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="problem-1-getting-the-library-id">Problem 1: Getting the library ID<a href="https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/#problem-1-getting-the-library-id" class="hash-link" aria-label="Direct link to Problem 1: Getting the library ID" title="Direct link to Problem 1: Getting the library ID" translate="no">​</a></h3>
<p>To mount a library, you need its ID. But there’s no admin interface for this.
Instead, you have to navigate to the library in a browser and start syncing it to your
device. On the sync dialog, you have the <strong>Copy library ID</strong> link:</p>
<div class="Container_cE8p"><div class="Dialog_opdr"><button class="CloseButton_wjUH" aria-label="Close">✕</button><div class="Heading_XLa_">We're syncing your files</div><div class="MainText_LDTP">We are connecting to OneDrive on your device. <br><span class="Link_jVuf LinkBold_gmVX">Copy library ID</span> to configure this library to sync automatically.</div><div class="Separator_ONJC"></div><div class="HintText_Z6rQ">If there is no response, you may need to <span class="Link_jVuf">install the latest version of OneDrive</span>.</div><div class="ActionRow_V9my"><button class="Button_yUFt">Close</button></div></div></div>
<p>However:</p>
<ul>
<li class="">To sync, you need read access. Most administrators that I know aren’t eager
to grant themselves unnecessary permissions.</li>
<li class="">The copy link may be missing. If so, the recommended way is to grab the ID from the
browser Developer Tools.</li>
<li class="">You may need to manually unescape the ID. The docs casually say that you should run
<code>[uri]::UnescapeDataString("Copied String")</code>.</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="problem-2-editing-policies-without-context">Problem 2: Editing policies without context<a href="https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/#problem-2-editing-policies-without-context" class="hash-link" aria-label="Direct link to Problem 2: Editing policies without context" title="Direct link to Problem 2: Editing policies without context" translate="no">​</a></h3>
<p>Once you have the ID, it’s time to configure the Group Policies. An ID value
looks like this:</p>
<p><code>tenantId=b456fb95‑9415‑4f96‑b039‑0f9fba5fea39&amp;siteId={7852d54e‑97c2‑4cea‑9ab8‑2abf9e51c41a}&amp;webId={60e7dfb7‑aa75‑44ea‑bd61‑2f65f3dfb0fb}&amp;listId={B81F17DE‑CA10‑4BF6‑8611‑458960EDFA20}&amp;webUrl=https%3A%2F%2Fexample%2sharepoint%2com%2Fsites%2FOffice%5FTemplates&amp;version=1</code></p>
<p>So here is the typical editing experience for those policies:</p>
<img class="Image_Jtan Border_PJCd" width="683" height="633" style="width:70%" src="https://blog.axiorema.com/assets/images/gpedit-automount-14a2d94be596a911fd87500eefe96e29.webp">
<p>Standard policy editors are unaware of your actual intent (to mount a specific server
object). And with long opaque IDs, a name-value table can quickly become unmaintainable,
even if you introduce a sophisticated naming scheme.</p>
<p>For example, how do you know if a half-year-old configuration still points to an existing
object on the server? Or check if any entries have outdated names?</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="problem-3-the-eight-hour-delay">Problem 3: The eight-hour delay<a href="https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/#problem-3-the-eight-hour-delay" class="hash-link" aria-label="Direct link to Problem 3: The eight-hour delay" title="Direct link to Problem 3: The eight-hour delay" translate="no">​</a></h3>
<p>Let’s say you configured the policy and want to test it.</p>
<p><em>Well, you can’t :)</em></p>
<p>At least, not immediately. Automount happens with a non-configurable delay of up to
8 hours. So, you either have to be <strong>very patient</strong> or deploy straight to production,
embracing cowboy administration style.</p>
<hr>
<p>Could Microsoft do better? It’s hard to say. Perhaps a few tweaks could improve
the situation:</p>
<ul>
<li class="">Using <code>base64url</code> in the IDs would eliminate the need for manual encoding.</li>
<li class="">Embedding additional metadata into the IDs could help present them more clearly
in the user interface.</li>
<li class="">A configurable delay interval would allow for easier testing and deployment.</li>
</ul>
<p>But these improvements would still be marginal because the <strong>core problem remains</strong>:
the policy distribution environment has no knowledge<sup><a href="https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/#user-content-fn-1-127b4f" id="user-content-fnref-1-127b4f" data-footnote-ref="true" aria-describedby="footnote-label" class="anchorTargetHideOnScrollNavbar_vjPI">1</a></sup> about the server. You still
can’t pick objects from the server or perform common actions (like checking
if the configuration is correct).</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="much-easier-in-a-self-hosted-environment">Much easier in a self-hosted environment<a href="https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/#much-easier-in-a-self-hosted-environment" class="hash-link" aria-label="Direct link to Much easier in a self-hosted environment" title="Direct link to Much easier in a self-hosted environment" translate="no">​</a></h2>
<p>There’s a saying: solving a hard engineering problem often requires changing
the requirements or flipping a core decision axis.</p>
<p>In our case, VisualDrive Server already is on an entirely different axis because
<strong>it’s self-hosted</strong>.</p>
<p>Essentially, it combines the server and the policy distribution environments
into one. All administration happens through a single management console.
The console configures the server itself and all OneDrive policies in the form
of <a href="https://www.axiorema.com/docs/visualdrive-server/latest/admin/installation/gpo-overview/" data-no-ext="true">Group Policy objects</a>.
We did have to write a full-featured Group Policy editor just for that:</p>
<div style="display:grid;grid-template-columns:repeat(2, 1fr);gap:0.8rem;width:95%"><div style="grid-column:1 / -1"><img class="Image_Jtan Border_PJCd" width="993" height="661" src="https://blog.axiorema.com/assets/images/manager-a28d482c3696fad117f8bb666c4efe79.png"></div><div><img class="Image_Jtan Border_PJCd" width="993" height="661" src="https://blog.axiorema.com/assets/images/gpo-list-8de814bc0710bb8b5f773433a14f3743.png"></div><div style="margin-left:1.25rem"><img class="Image_Jtan Border_PJCd" width="837" height="603" src="https://blog.axiorema.com/assets/images/gpo-configuration-deb419e16798b94fa146c3923a05a0f3.png"></div></div>
<p>Because we control both environments, sharing state between them becomes an ordinary
technical task. And suddenly, all of the original problems have simple solutions:</p>
<div class="Container_P0iq"><ol>
<li class="">
<p><strong>Getting the library ID is no longer needed</strong></p>
<p>The administrator can simply pick the appropriate object from a list.</p>
</li>
<li class="">
<p><strong>Context is no longer lost when editing policies</strong></p>
<p>Implementing an enhanced policy editor (where values map to actual objects on the
server) becomes relatively straightforward. The shown state is always up-to-date.
Configuration issues, such as dangling entries, are detected automatically during
the mapping.</p>
</li>
<li class="">
<p><strong>Automount delay can be reduced to zero</strong></p>
<p>In a self-hosted environment, it’s technically possible to reduce the
automount delay to <code>0</code>. This is a reasonable default, because OneDrive works
with local network speeds, and without any kind of throttling or rate-limiting.</p>
</li>
</ol></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="passing-the-state-around">Passing the state around<a href="https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/#passing-the-state-around" class="hash-link" aria-label="Direct link to Passing the state around" title="Direct link to Passing the state around" translate="no">​</a></h3>
<p>While sharing state should be an ordinary technical task, our architecture made it
slightly peculiar.</p>
<p>VisualDrive Server uses what we call a <strong>macroservice</strong> architecture. The core service
(<code>vdrivesvc.exe</code>) encloses all of the state. All background and regular operations run
as embedded pseudo-services within <code>vdrivesvc</code>.</p>
<div class="theme-admonition theme-admonition-tip admonition_Gfwi alert alert--success"><div class="admonitionContent_UjKb"><p>We used to jokingly downplay the role of many small Win32 services in our other
products by calling them “microservices”. The inverse of that is a
“macroservice”. Somehow, the term stuck.</p></div></div>
<p><svg width="24" height="24" viewBox="0 0 16 16" style="vertical-align:middle"><defs><linearGradient id="ic_fluent_checkmark_circle_16_color__a" x1="2.42857" y1="4.25" x2="10.71" y2="12.8541" gradientUnits="userSpaceOnUse"><stop stop-color="#52D17C"></stop><stop offset="1" stop-color="#22918B"></stop></linearGradient><linearGradient id="ic_fluent_checkmark_circle_16_color__b" x1="6.12018" y1="6.44888" x2="7.07576" y2="11.2099" gradientUnits="userSpaceOnUse"><stop stop-color="#fff"></stop><stop offset="1" stop-color="#E3FFD9"></stop></linearGradient></defs><path fill="url(#ic_fluent_checkmark_circle_16_color__a)" d="M2 8C2 4.68629 4.68629 2 8 2C11.3137 2 14 4.68629 14 8C14 11.3137 11.3137 14 8 14C4.68629 14 2 11.3137 2 8Z"></path><path fill="url(#ic_fluent_checkmark_circle_16_color__b)" d="M10.1203 6.16401L7.24953 9.04245L5.85355 7.64648C5.65829 7.45121 5.34171 7.45121 5.14645 7.64648C4.95118 7.84174 4.95118 8.15832 5.14645 8.35358L6.89645 10.1036C7.09189 10.299 7.40884 10.2988 7.60403 10.1031L10.8283 6.87017C11.0233 6.67465 11.0229 6.35806 10.8274 6.16306C10.6319 5.96806 10.3153 5.96849 10.1203 6.16401Z"></path></svg> The biggest advantage of this model is exclusive access to the
internal database. With a macroservice, every internal component accesses the content
directly without any inter-process communication (IPC).</p>
<p><svg width="24" height="24" viewBox="0 0 16 16" style="vertical-align:middle"><defs><linearGradient id="ic_fluent_dismiss_circle_16_color__a" x1="3.875" y1="2.75" x2="13" y2="16" gradientUnits="userSpaceOnUse"><stop stop-color="#E5484D"></stop><stop offset="1" stop-color="#B54548"></stop></linearGradient><linearGradient id="ic_fluent_dismiss_circle_16_color__b" x1="6.01126" y1="8.19887" x2="8.35442" y2="10.6354" gradientUnits="userSpaceOnUse"><stop stop-color="#FDFDFD"></stop><stop offset="1" stop-color="#FECBE6"></stop></linearGradient></defs><path fill="url(#ic_fluent_dismiss_circle_16_color__a)" d="M8 2C11.3137 2 14 4.68629 14 8C14 11.3137 11.3137 14 8 14C4.68629 14 2 11.3137 2 8C2 4.68629 4.68629 2 8 2Z"></path><path fill="url(#ic_fluent_dismiss_circle_16_color__b)" d="M5.89645 5.89645C6.07001 5.72288 6.33944 5.7036 6.53431 5.83859L6.60355 5.89645L8 7.293L9.39645 5.89645C9.57001 5.72288 9.83944 5.7036 10.0343 5.83859L10.1036 5.89645C10.2771 6.07001 10.2964 6.33944 10.1614 6.53431L10.1036 6.60355L8.707 8L10.1036 9.39645C10.2771 9.57001 10.2964 9.83944 10.1614 10.0343L10.1036 10.1036C9.92999 10.2771 9.66056 10.2964 9.46569 10.1614L9.39645 10.1036L8 8.707L6.60355 10.1036C6.42999 10.2771 6.16056 10.2964 5.96569 10.1614L5.89645 10.1036C5.72288 9.92999 5.7036 9.66056 5.83859 9.46569L5.89645 9.39645L7.293 8L5.89645 6.60355C5.72288 6.42999 5.7036 6.16056 5.83859 5.96569L5.89645 5.89645Z"></path></svg> The obvious downside is reduced isolation: a crash anywhere within
the service takes everything down.</p>
<p><svg width="24" height="24" viewBox="0 0 16 16" style="vertical-align:middle"><defs><linearGradient id="ic_fluent_dismiss_circle_16_color__a" x1="3.875" y1="2.75" x2="13" y2="16" gradientUnits="userSpaceOnUse"><stop stop-color="#E5484D"></stop><stop offset="1" stop-color="#B54548"></stop></linearGradient><linearGradient id="ic_fluent_dismiss_circle_16_color__b" x1="6.01126" y1="8.19887" x2="8.35442" y2="10.6354" gradientUnits="userSpaceOnUse"><stop stop-color="#FDFDFD"></stop><stop offset="1" stop-color="#FECBE6"></stop></linearGradient></defs><path fill="url(#ic_fluent_dismiss_circle_16_color__a)" d="M8 2C11.3137 2 14 4.68629 14 8C14 11.3137 11.3137 14 8 14C4.68629 14 2 11.3137 2 8C2 4.68629 4.68629 2 8 2Z"></path><path fill="url(#ic_fluent_dismiss_circle_16_color__b)" d="M5.89645 5.89645C6.07001 5.72288 6.33944 5.7036 6.53431 5.83859L6.60355 5.89645L8 7.293L9.39645 5.89645C9.57001 5.72288 9.83944 5.7036 10.0343 5.83859L10.1036 5.89645C10.2771 6.07001 10.2964 6.33944 10.1614 6.53431L10.1036 6.60355L8.707 8L10.1036 9.39645C10.2771 9.57001 10.2964 9.83944 10.1614 10.0343L10.1036 10.1036C9.92999 10.2771 9.66056 10.2964 9.46569 10.1614L9.39645 10.1036L8 8.707L6.60355 10.1036C6.42999 10.2771 6.16056 10.2964 5.96569 10.1614L5.89645 10.1036C5.72288 9.92999 5.7036 9.66056 5.83859 9.46569L5.89645 9.39645L7.293 8L5.89645 6.60355C5.72288 6.42999 5.7036 6.16056 5.83859 5.96569L5.89645 5.89645Z"></path></svg> The <strong>far less obvious</strong> downside is the development inertia. When
everything folds into one single service, you start to actively resist adding external
endpoints. Why bother building an IPC infrastructure when you can add another
pseudo-service?</p>
<p><em>Unfortunately, this concept has its limits.</em></p>
<p>To configure the automount policies, the management console (<code>vdrivemgr</code>) needs to
know about the items on the server. And you cannot fold the entire console into
a background service.</p>
<p>So, we had to <a class="" href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/">shave the yak</a> and finally
implement an actual IPC infrastructure. Under the hood, it is nothing out of the ordinary.
We use a named pipe with an appropriate security descriptor. The client (management
console) and the server communicate by exchanging JSON messages:</p>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="result-a-better-automount-experience">Result: a better automount experience<a href="https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/#result-a-better-automount-experience" class="hash-link" aria-label="Direct link to Result: a better automount experience" title="Direct link to Result: a better automount experience" translate="no">​</a></h2>
<p>Thanks to our self-hostedness<sup><a href="https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/#user-content-fn-2-127b4f" id="user-content-fnref-2-127b4f" data-footnote-ref="true" aria-describedby="footnote-label" class="anchorTargetHideOnScrollNavbar_vjPI">2</a></sup>, we were able to expose the server state to the
management console and provide a much more intuitive experience for the automount
configuration.</p>
<p>It consists of three parts:</p>
<div class="Container_P0iq Timeline_T1mj"><ol>
<li class="">
<p>The <strong>New Drive Automount GPO</strong> wizard can be used to quickly create a new
policy in your environment. Most of the configuration is simply picking the
locations you want to mount.</p>
<div style="margin-top:1.5em"></div>
<img class="Image_Jtan Border_PJCd" width="689" height="550" style="width:70%" src="https://blog.axiorema.com/assets/images/automount-wizard-3ae3fd07557d28fb76017fd1dab0443c.webp">
</li>
<li class="">
<p>The <strong>Drive Automount Policy Editor</strong> lets you review and update policies
without losing context. Because the shown items are mapped to the drive
objects on the server, you actually see what you are editing.</p>
<div style="margin-top:1.5em"></div>
<img class="Image_Jtan" width="840" height="605" style="width:85%" src="https://blog.axiorema.com/assets/images/automount-editor-156da6d58fe0f9df03d1c83c162b86df.webp">
</li>
<li class="">
<p>Automount <strong>happens immediately</strong>, without unpredictable delays.
There’s no need to wait 8 hours to see if the configuration works.</p>
</li>
</ol></div>
<div style="margin-top:2.5em"></div>
<p>Together, this results in a standard, even a bit boring Windows administrative
experience. Seeing it for the first time, you might wonder what the big deal is.
Unless you know or have used the alternative, of course.</p>
<hr>
<!-- -->
<section data-footnotes="true" class="footnotes"><h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI sr-only" id="footnote-label">Footnotes<a href="https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/#footnote-label" class="hash-link" aria-label="Direct link to Footnotes" title="Direct link to Footnotes" translate="no">​</a></h2>
<ol>
<li class="anchorTargetHideOnScrollNavbar_vjPI" id="user-content-fn-1-127b4f">
<p>Theoretically, some knowledge could be passed internally between SharePoint
and Intune. But that’s challenging and even if done, it wouldn’t solve
the issue for environments with regular Group Policies. <a href="https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/#user-content-fnref-1-127b4f" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li class="anchorTargetHideOnScrollNavbar_vjPI" id="user-content-fn-2-127b4f">
<p>Is that an actual word? <a href="https://blog.axiorema.com/engineering/we-improved-onedrive-folder-automount/#user-content-fnref-2-127b4f" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
            <category>onedrive</category>
            <category>automount</category>
            <category>visualdrive-server</category>
            <category>gpo</category>
        </item>
        <item>
            <title><![CDATA[Don’t shave that yak! (How we added Go to Visual Studio)]]></title>
            <link>https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/</link>
            <guid>https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/</guid>
            <pubDate>Fri, 27 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Getting sidetracked is a necessary part of the engineering experience.]]></description>
            <content:encoded><![CDATA[<p><strong>Yak shaving</strong><sup><a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#user-content-fn-1-28929d" id="user-content-fnref-1-28929d" data-footnote-ref="true" aria-describedby="footnote-label" class="anchorTargetHideOnScrollNavbar_vjPI">1</a></sup> describes doing some seemingly useless task that is necessary
to complete another task, which is necessary to complete other tasks, which will
eventually allow you to complete your initial goal.</p>
<p>In our case, the goal was building <a href="https://www.axiorema.com/visualdock-server/" data-no-ext="true">VisualDock Server</a>
with the help of Visual Studio (the <em>original</em> one, not VS Code). VisualDock relies
on Moby. Moby is written in Go. But Visual Studio doesn’t support Go.</p>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="wheres-our-yak">Where’s our yak?<a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#wheres-our-yak" class="hash-link" aria-label="Direct link to Where’s our yak?" title="Direct link to Where’s our yak?" translate="no">​</a></h2>
<p>Most of VisualDock Server is written in <strong>C#</strong>, with a lot of <strong>MSBuild</strong> magic happening
behind the scenes. This makes using Visual Studio a pretty natural choice.</p>
<p>However, Visual Studio is like a limousine. If you do .NET and C++ development, occasionally
throwing in some TypeScript, you get a lavish ride from point A to B. But if you want
to go slightly off-road, you gotta do something about that suspension beforehand<sup><a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#user-content-fn-2-28929d" id="user-content-fnref-2-28929d" data-footnote-ref="true" aria-describedby="footnote-label" class="anchorTargetHideOnScrollNavbar_vjPI">2</a></sup>.</p>
<div class="theme-admonition theme-admonition-tip admonition_Gfwi alert alert--success"><div class="admonitionContent_UjKb"><p>In our case, the off-road exists due to depending on the Moby project, written
in <strong>Go</strong>. We regularly need to browse its code, jump to definitions and navigate
through references. A proper test runner and debugging support have their use as well.</p></div></div>
<p><strong>Go</strong> isn’t the usual guest in Visual Studio, and the only thing offered out of
the box is the TextMate-based syntax highlighting. So, for a proper development experience,
you need to keep two different IDEs and switch back and forth between them. The cost of
that tends to stack up, especially when aiming for a coherent development environment
across the team.</p>
<p><em>“Wouldn’t it help if we built an extension with a minimal Go integration for Visual Studio?”</em></p>
<p>Surely, that would help. We have experience in developing VS extensions, which would
likely make it a weekend-size task. But isn’t that a massive detour from building
the actual product?</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="maybe-this-yak-is-different">Maybe this yak is different?<a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#maybe-this-yak-is-different" class="hash-link" aria-label="Direct link to Maybe this yak is different?" title="Direct link to Maybe this yak is different?" translate="no">​</a></h2>
<!-- -->
<p>There’s the yak: you need a Go integration plugin, <strong>which</strong> will help you
work with a subcomponent written in Go, <strong>which</strong> is responsible for a significant
part of your business logic, <strong>which</strong> is needed to build your final product.</p>
<p>Conventional wisdom says that if you find yourself with a dependency chain this long,
you need to cut it, find an alternative or a compromise.</p>
<p>But… there are benefits in unifying the development environment, and, as it happened,
we were in the right mood to give it a try.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="how-did-we-shave-the-yak">How did we shave the yak?<a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#how-did-we-shave-the-yak" class="hash-link" aria-label="Direct link to How did we shave the yak?" title="Direct link to How did we shave the yak?" translate="no">​</a></h2>
<p>We decided to make a simple Go integration extension for Visual Studio.</p>
<p>Visual Studio offers decent <a href="https://microsoft.github.io/language-server-protocol/" target="_blank" rel="noopener noreferrer" class="">Language Server Protocol (LSP)</a> support. So, building
a language integration extension is mostly about properly wiring things up and deciding
on the feature set.</p>
<p>In case of Go, the standard language server is <strong>Gopls</strong>, and it’s offered by the
core language team. We just had to teach it to speak with Visual Studio.</p>
<!-- -->
<p>Surprisingly, the actual implementation is rather uninteresting to write about.
But we learnt a few things along the way, and they seem to be worth mentioning:</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="1-empty-vsix-extension-project-2026-edition">1. Empty VSIX extension project: 2026 edition<a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#1-empty-vsix-extension-project-2026-edition" class="hash-link" aria-label="Direct link to 1. Empty VSIX extension project: 2026 edition" title="Direct link to 1. Empty VSIX extension project: 2026 edition" translate="no">​</a></h3>
<p>Pretty much everyone in the .NET ecosystem has moved to so-called SDK-style projects.
These can be identified by the <code>&lt;Project Sdk="..."&gt;</code> preamble.</p>
<p>A VSIX package is the standard way to bundle and distribute Visual Studio extensions.
For a long time, the default VSIX project template in Visual Studio <a href="https://developercommunity.visualstudio.com/t/vsix-project-with-sdk-style-csproj/1572145" target="_blank" rel="noopener noreferrer" class="">wasn’t using
the SDK-style</a>, but it seems there is finally an official way
to do it.</p>
<p>The trick is to reference the <code>Microsoft.VisualStudio.Sdk.Build</code> SDK and specify a custom
<code>TargetFramework</code>, like <code>vs17.12</code>. Here is a quick snippet of what that modern project
file looks like:</p>
<div class="language-xml codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-xml codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">Project</span><span class="token tag" style="color:rgb(128, 0, 0)"> </span><span class="token tag attr-name" style="color:rgb(255, 0, 0)">Sdk</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(4, 81, 165)">=</span><span class="token tag attr-value punctuation" style="color:rgb(4, 81, 165)">"</span><span class="token tag attr-value" style="color:rgb(128, 0, 0)">Microsoft.VisualStudio.Sdk.Build</span><span class="token tag attr-value punctuation" style="color:rgb(4, 81, 165)">"</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">PropertyGroup</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">RootNamespace</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">VsGo</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">RootNamespace</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">AssemblyName</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">VsGo</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">AssemblyName</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">AppendRuntimeIdentifierToOutputPath</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">false</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">AppendRuntimeIdentifierToOutputPath</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">AppendTargetFrameworkToOutputPath</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">false</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">AppendTargetFrameworkToOutputPath</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">TargetFramework</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">vs17.12</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">TargetFramework</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">Platforms</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">AnyCPU</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">Platforms</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">PropertyGroup</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">PropertyGroup</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">GeneratePkgDefFile</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">true</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">GeneratePkgDefFile</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">UseCodebase</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">true</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">UseCodebase</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">IncludeAssemblyInVSIXContainer</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">true</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">IncludeAssemblyInVSIXContainer</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">IncludeDebugSymbolsInVSIXContainer</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">false</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">IncludeDebugSymbolsInVSIXContainer</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">IncludeDebugSymbolsInLocalVSIXDeployment</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">false</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">IncludeDebugSymbolsInLocalVSIXDeployment</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">CopyBuildOutputToOutputDirectory</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">true</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">CopyBuildOutputToOutputDirectory</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">CopyOutputSymbolsToOutputDirectory</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">true</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">CopyOutputSymbolsToOutputDirectory</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">StartAction</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">Program</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">StartAction</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">StartProgram</span><span class="token tag" style="color:rgb(128, 0, 0)"> </span><span class="token tag attr-name" style="color:rgb(255, 0, 0)">Condition</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(4, 81, 165)">=</span><span class="token tag attr-value punctuation" style="color:rgb(4, 81, 165)">"</span><span class="token tag attr-value punctuation" style="color:rgb(4, 81, 165)">'</span><span class="token tag attr-value" style="color:rgb(128, 0, 0)">$(DevEnvDir)' != ''</span><span class="token tag attr-value punctuation" style="color:rgb(4, 81, 165)">"</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">$(DevEnvDir)devenv.exe</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">StartProgram</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;</span><span class="token tag" style="color:rgb(128, 0, 0)">StartArguments</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain">/rootsuffix Exp</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">StartArguments</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  </span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">PropertyGroup</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  …</span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&lt;/</span><span class="token tag" style="color:rgb(128, 0, 0)">Project</span><span class="token tag punctuation" style="color:rgb(4, 81, 165)">&gt;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="2-unified-settings-are-the-new-way-to-go">2. Unified settings are the new way to go<a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#2-unified-settings-are-the-new-way-to-go" class="hash-link" aria-label="Direct link to 2. Unified settings are the new way to go" title="Direct link to 2. Unified settings are the new way to go" translate="no">​</a></h3>
<p>Occasionally, Visual Studio picks up a thing or two from VS Code. This time, it comes in
the form of the updated <a href="https://devblogs.microsoft.com/visualstudio/unifiedsettings/" target="_blank" rel="noopener noreferrer" class="">Unified settings</a>:</p>
<img class="Image_Jtan Border_PJCd" width="873" height="672" style="width:75%" src="https://blog.axiorema.com/assets/images/vs-unified-settings-6c5df8735f1983a1028d3e378589b118.webp">
<p>Extension writers are pretty much forced to use them, because sticking to the older
pattern will cause your extension to be labeled “Legacy” in the Settings
window.</p>
<p>We still have some work to do here, because implementing these new settings is
currently undocumented. Hoping to post on this topic soon.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="3-visual-studio-cuts-some-corners-in-its-lsp-implementation">3. Visual Studio cuts some corners in its LSP implementation<a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#3-visual-studio-cuts-some-corners-in-its-lsp-implementation" class="hash-link" aria-label="Direct link to 3. Visual Studio cuts some corners in its LSP implementation" title="Direct link to 3. Visual Studio cuts some corners in its LSP implementation" translate="no">​</a></h3>
<p>In the LSP protocol, the client (Visual Studio) provides the server (Gopls) with different
configuration settings. The synchronization model is twofold:</p>
<ul>
<li class="">
<p>The client can send the <a href="https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_didChangeConfiguration" target="_blank" rel="noopener noreferrer" class=""><code>workspace.didChangeConfiguration</code></a>
request to notify the server that the settings have changed.</p>
</li>
<li class="">
<p>The server can fetch the configuration settings it needs from the client with
the help of the <a href="https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_configuration" target="_blank" rel="noopener noreferrer" class=""><code>workspace.configuration</code></a> request.</p>
</li>
</ul>
<p>Unfortunately, the Visual Studio LSP client doesn’t implement the pull part of
this model, and doesn’t support <code>workspace.configuration</code> requests. This results
in Gopls not picking up some of the configuration settings.</p>
<p>We filed an issue for this, and hope that it will get fixed at some point.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-shaved-yak-">The shaved yak 🐂<a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#the-shaved-yak-" class="hash-link" aria-label="Direct link to The shaved yak 🐂" title="Direct link to The shaved yak 🐂" translate="no">​</a></h2>
<p>In its current form, our extension provides context-aware syntax highlighting, code
completion, the ability to navigate to definitions, find references, and rename things:</p>
<img class="Image_Jtan Border_PJCd" width="1280" height="840" style="width:75%" src="https://blog.axiorema.com/assets/images/vsgo-find-references-11e33a221d54d279d409a58c71c155fe.gif">
<p>It isn’t eye-catching, but gets the work done. A couple of things are still
on the roadmap.</p>
<div class="theme-admonition theme-admonition-tip admonition_Gfwi alert alert--success"><div class="admonitionContent_UjKb"><p>If you would like to try out the extension, search for <kbd>Go</kbd> on the Visual Studio Marketplace.
You can’t miss it.</p></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="was-it-worth-it">Was it worth it?<a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#was-it-worth-it" class="hash-link" aria-label="Direct link to Was it worth it?" title="Direct link to Was it worth it?" translate="no">​</a></h2>
<p>Contrary to the title, we chose to <em>shave the yak</em> and build an extension to manage all
our code from one IDE.</p>
<p>There is some controversy around whether yak shaving is a <strong>good thing</strong>. Opponents say that
it indicates a long dependency chain that can be avoided entirely by making better decisions.
In this case, some of the decisions (e.g., using Moby) are unavoidable, thus making the argument
less applicable.</p>
<p>Overall, there are both good and bad aspects. Maybe it’s too early for a
retrospective, but the benefits seem to outweigh the drawbacks:</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="-the-bads"><svg width="24" height="24" viewBox="0 0 16 16" style="vertical-align:middle"><defs><linearGradient id="ic_fluent_dismiss_circle_16_color__a" x1="3.875" y1="2.75" x2="13" y2="16" gradientUnits="userSpaceOnUse"><stop stop-color="#E5484D"></stop><stop offset="1" stop-color="#B54548"></stop></linearGradient><linearGradient id="ic_fluent_dismiss_circle_16_color__b" x1="6.01126" y1="8.19887" x2="8.35442" y2="10.6354" gradientUnits="userSpaceOnUse"><stop stop-color="#FDFDFD"></stop><stop offset="1" stop-color="#FECBE6"></stop></linearGradient></defs><path fill="url(#ic_fluent_dismiss_circle_16_color__a)" d="M8 2C11.3137 2 14 4.68629 14 8C14 11.3137 11.3137 14 8 14C4.68629 14 2 11.3137 2 8C2 4.68629 4.68629 2 8 2Z"></path><path fill="url(#ic_fluent_dismiss_circle_16_color__b)" d="M5.89645 5.89645C6.07001 5.72288 6.33944 5.7036 6.53431 5.83859L6.60355 5.89645L8 7.293L9.39645 5.89645C9.57001 5.72288 9.83944 5.7036 10.0343 5.83859L10.1036 5.89645C10.2771 6.07001 10.2964 6.33944 10.1614 6.53431L10.1036 6.60355L8.707 8L10.1036 9.39645C10.2771 9.57001 10.2964 9.83944 10.1614 10.0343L10.1036 10.1036C9.92999 10.2771 9.66056 10.2964 9.46569 10.1614L9.39645 10.1036L8 8.707L6.60355 10.1036C6.42999 10.2771 6.16056 10.2964 5.96569 10.1614L5.89645 10.1036C5.72288 9.92999 5.7036 9.66056 5.83859 9.46569L5.89645 9.39645L7.293 8L5.89645 6.60355C5.72288 6.42999 5.7036 6.16056 5.83859 5.96569L5.89645 5.89645Z"></path></svg> The bads<a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#-the-bads" class="hash-link" aria-label="Direct link to -the-bads" title="Direct link to -the-bads" translate="no">​</a></h3>
<ul>
<li class="">It was a distraction from the main project.</li>
<li class="">It consumed some time and may be viewed as a form of procrastination.</li>
<li class="">It may continue siphoning time for future maintenance, such as adding debugging support.</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="-the-goods"><svg width="24" height="24" viewBox="0 0 16 16" style="vertical-align:middle"><defs><linearGradient id="ic_fluent_checkmark_circle_16_color__a" x1="2.42857" y1="4.25" x2="10.71" y2="12.8541" gradientUnits="userSpaceOnUse"><stop stop-color="#52D17C"></stop><stop offset="1" stop-color="#22918B"></stop></linearGradient><linearGradient id="ic_fluent_checkmark_circle_16_color__b" x1="6.12018" y1="6.44888" x2="7.07576" y2="11.2099" gradientUnits="userSpaceOnUse"><stop stop-color="#fff"></stop><stop offset="1" stop-color="#E3FFD9"></stop></linearGradient></defs><path fill="url(#ic_fluent_checkmark_circle_16_color__a)" d="M2 8C2 4.68629 4.68629 2 8 2C11.3137 2 14 4.68629 14 8C14 11.3137 11.3137 14 8 14C4.68629 14 2 11.3137 2 8Z"></path><path fill="url(#ic_fluent_checkmark_circle_16_color__b)" d="M10.1203 6.16401L7.24953 9.04245L5.85355 7.64648C5.65829 7.45121 5.34171 7.45121 5.14645 7.64648C4.95118 7.84174 4.95118 8.15832 5.14645 8.35358L6.89645 10.1036C7.09189 10.299 7.40884 10.2988 7.60403 10.1031L10.8283 6.87017C11.0233 6.67465 11.0229 6.35806 10.8274 6.16306C10.6319 5.96806 10.3153 5.96849 10.1203 6.16401Z"></path></svg> The goods<a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#-the-goods" class="hash-link" aria-label="Direct link to -the-goods" title="Direct link to -the-goods" translate="no">​</a></h3>
<ul>
<li class="">It was a distraction from the main project :)</li>
<li class="">Being able to work with all your code in one IDE is a fairly important thing, with the benefits accumulating over time.</li>
<li class="">We built something that might be useful to other developers, learning a thing or two along the way.</li>
<li class="">I finally get to reference the legendary xkcd comic:</li>
</ul>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28 16"><path fill="#fff" d="m.242 1.167 1.87.026.671-.453.423-.16L4.345.399l.922-.07L7.538.244l1.506.09 1.205.208.61.227.338.171.42.317 16.091-.07v14.65l-27.41-.013.04-14.375z"></path><path d="M8.709 1.79c.171.094.263.279.157.449a.414.414 0 0 1-.595.104c.011-.327.032-.62-.009-.937a.51.51 0 0 1 .477-.048c.08.03.14.112.137.195-.004.1-.071.157-.167.236m.027-.18c.025-.031.034-.07.017-.102-.052-.095-.27-.098-.364-.048l-.006.825c.143.066.332.02.399-.13a.19.19 0 0 0-.056-.22c-.133-.112-.285-.01-.293-.115-.006-.086.182-.055.303-.21M2.967 1.893c-.038.134.029.475-.067.49-.031.005-.061-.026-.06-.075.004-.304.016-.596.002-.9q-.002-.046.022-.067c.146-.126.067.38.103.441l.4-.032c.031-.114-.031-.421.06-.44.031-.007.06.027.06.074-.006.312-.02.612.002.923.003.034-.029.056-.047.066-.109.056-.058-.436-.078-.514-.136.004-.26.015-.397.034M6.06 3.66c-.024-.071-.263-.94-.113-.853.08.046.12.597.202.777.057-.07.076-.252.156-.272.083-.02.11.226.178.271.091-.255.112-.505.149-.76a.07.07 0 0 1 .046-.057c.018-.005.068.014.064.048-.021.156-.108.915-.244.94-.033.006-.069-.013-.087-.047l-.1-.186c-.062.075-.072.23-.158.23-.04 0-.077-.04-.093-.09M7.94 3.72a.65.65 0 0 0-.37-.39l-.009.353c0 .037-.02.06-.038.066-.037.012-.072-.015-.07-.066.009-.244.024-.477.004-.718-.002-.026-.065-.066-.033-.102.145-.159.47-.188.568-.011.038.07.039.151.002.216-.057.104-.159.152-.266.211.481.375.242.517.212.44Zm-.042-.71c.037-.063 0-.134-.061-.155-.065-.022-.22-.035-.257.037-.046.092 0 .214 0 .306.13-.025.25-.073.318-.187M6.398 1.922c-.066-.033-.211.031-.22-.05-.014-.106.264-.09.304-.031.083.118-.062.452-.202.501a.28.28 0 0 1-.248-.03c-.297-.193-.337-.603-.113-.874.144-.173.407-.184.546-.009.021.026.004.067-.015.077-.053.03-.205-.196-.39-.048a.48.48 0 0 0-.023.722c.064.059.166.09.232.031.08-.07.109-.172.129-.289ZM9.459 1.939c-.12-.007-.236.01-.35.034-.044.123-.02.375-.106.378-.018 0-.06-.02-.057-.052.021-.183.109-.903.29-.951.145-.038.266.283.296.414.185.8-.019.568-.018.572zm-.028-.133c-.037-.14-.072-.256-.17-.346-.077.116-.1.24-.125.383a.9.9 0 0 0 .295-.037M10.513 1.82c.631.464.406.635.342.52a1 1 0 0 0-.422-.417c-.035.12.047.45-.057.45-.03.001-.053-.029-.054-.068l-.006-.872c0-.037.02-.06.037-.066.039-.012.067.024.069.067l.01.293c.12-.034.464-.548.43-.267-.095.134-.208.224-.35.36M8.314 3.22c.567.395.407.678.322.518a.94.94 0 0 0-.394-.42l-.006.387c0 .031-.021.05-.036.055-.03.01-.068-.013-.069-.054l-.016-.896c0-.026.026-.045.038-.05.024-.008.057.016.06.049l.03.325c.119-.059.364-.391.429-.348.108.071-.279.356-.359.434ZM3.729 1.874c-.019.118-.014.233-.012.363.107.002.487-.09.51.02.006.027-.018.06-.06.06-.313-.005-.575.115-.568-.035.014-.301.027-.588-.006-.89.114-.044.591-.118.614-.02.026.112-.327.04-.488.1-.011.093 0 .182.008.283l.2-.007c.038-.001.066.017.065.053-.004.09-.142.045-.263.073ZM6.719 1.885c-.011.12-.02.23-.02.352.114.005.463-.088.52.009.011.02-.002.073-.037.072-.376-.004-.618.113-.602-.06.028-.295.042-.573.006-.87.126-.037.563-.114.604-.013.049.118-.301.023-.476.096l.003.287c.066.024.212-.041.236.038.01.034-.012.068-.053.072zM5.289 3.748c-.147.098-.333-.008-.383-.16a.74.74 0 0 1 .129-.681c.073-.092.179-.103.267-.035.061.047.13.085.168.164a.57.57 0 0 1-.181.712Zm-.027-.108a.48.48 0 0 0 .141-.471c-.018-.086-.146-.256-.242-.21-.173.073-.274.591-.06.7.046.022.113.026.161-.02"></path><path d="M7.25 3.655a.26.26 0 0 1-.26.091c-.286-.065-.296-.562-.084-.866.075-.106.196-.111.293-.03.236.201.261.562.052.805Zm-.097-.051a.473.473 0 0 0-.003-.654c-.039-.04-.117-.067-.155-.011-.145.217-.197.613-.007.69.04.017.124.02.165-.025M9.78 2.081a.28.28 0 0 0 .172.156c.14.054.236-.145.293-.046.035.06-.148.224-.361.14a.38.38 0 0 1-.222-.247c-.086-.297.111-.79.406-.72.078.019.179.133.126.186-.066.065-.08-.078-.173-.085-.144-.01-.343.352-.24.616M4.622 2.35c-.145.12-.058-.317-.103-.423-.049-.115-.315-.49-.254-.536.104-.08.19.282.31.396.09-.082.263-.511.332-.5.043.008.051.054.03.094l-.278.521c-.044.083.01.41-.037.448M7.576 2.29c-.002.04-.032.055-.05.057-.028.002-.06-.026-.06-.065l.022-.795c-.083-.025-.225.054-.26-.017-.012-.027.007-.07.045-.075.116-.016.617-.097.655-.023.062.12-.222.06-.317.091zM4.686 3.694q0 .086-.051.09c-.042.002-.06-.038-.059-.08l.012-.793-.246.026c-.035.004-.06-.016-.067-.042-.004-.018.007-.056.043-.061l.621-.083a.08.08 0 0 1 .067.025c.017.02.012.07-.025.075l-.287.038zM5.163 1.944c-.001.053-.041.073-.062.068-.03-.005-.05-.041-.047-.079.015-.217.02-.424.025-.636 0-.026.06-.027.07-.013.009.014.03.035.029.065zM9.001 2.778c.004.1.02.628-.051.631-.022.002-.06-.013-.06-.053l.008-.616c0-.028.04-.038.056-.036.025.004.046.038.047.074"></path><circle cx="8.948" cy="3.651" r="0.097"></circle><circle cx="5.11" cy="2.26" r="0.093"></circle><path d="M9.559 13.034c-.038.12.035.627-.034.663-.02.01-.074-.001-.074-.034l-.008-.874c0-.026.062-.032.075-.02s.038.03.052.057l.367.667.03-.713q.002-.042.023-.062c.02-.017.05-.022.071.001.015.016.016.045.015.077l-.027.818c-.002.04-.02.079-.05.086a.09.09 0 0 1-.094-.041zM7.6 13.676c-.104.08-.073-.296-.44-.43-.048.13.03.427-.063.457-.035.01-.066-.025-.064-.073l.018-.702c.001-.036-.057-.11-.026-.142.107-.112.296-.13.438-.086a.23.23 0 0 1 .157.164c.045.172-.102.299-.277.354.13.065.354.382.256.458Zm-.13-.652c.06-.056.069-.157.002-.2a.31.31 0 0 0-.327.007l.02.298a.4.4 0 0 0 .306-.105M6.919 13.692c-.082.096-.095-.306-.427-.416-.02.102.032.45-.089.417-.018-.005-.035-.027-.034-.063.005-.252.022-.491.005-.74-.002-.03-.048-.08-.012-.11.168-.136.528-.121.588.1.044.163-.132.289-.298.35.137.085.356.357.267.462m-.091-.711c.046-.072-.007-.147-.07-.164a.38.38 0 0 0-.27.016c-.007.11-.001.207.006.312.127-.009.259-.048.334-.164M6.152 13.289c-.118-.003-.232.019-.352.033-.052.102-.02.345-.098.38-.019.008-.069-.015-.065-.051.018-.171.098-.967.344-.933.26.036.382.964.265.986-.107.02-.043-.264-.094-.415m-.022-.116c-.031-.138-.061-.258-.165-.352-.096.116-.118.248-.146.383zM3.221 13.645a.29.29 0 0 1-.284.08.3.3 0 0 1-.197-.198c-.109-.39.14-.83.301-.806.165.023.31.165.355.324a.6.6 0 0 1-.175.6m.09-.451c.014-.128-.128-.392-.284-.34-.18.035-.344.707-.045.77.172.038.304-.2.329-.43M9.171 13.647a.27.27 0 0 1-.276.064c-.29-.094-.257-.602-.069-.871.038-.054.114-.145.188-.128.182.04.327.208.353.392a.62.62 0 0 1-.196.543m.096-.427c.025-.127-.108-.419-.273-.367-.172-.004-.359.73-.018.759.163.013.257-.217.291-.392M3.583 13.637c0 .04-.03.063-.054.064-.03.002-.052-.029-.051-.066.008-.269.017-.53.01-.804 0-.035.017-.062.04-.067.036-.008.064.02.064.064l.007.306q.2.007.392-.02c.01-.11-.032-.39.062-.395.029-.001.056.025.055.063l-.01.447c-.002.137-.005.265.014.4.005.039-.011.067-.035.076-.137.051-.07-.38-.088-.474a2 2 0 0 0-.395.024zM5.282 12.854c-.21.22-.273.66-.026.75.143.052.218-.052.295-.063.02-.003.062.037.042.062a.33.33 0 0 1-.364.105.35.35 0 0 1-.232-.286c-.052-.314.155-.756.426-.717.06.01.136.05.165.124a.07.07 0 0 1-.022.081c-.064.047-.08-.086-.146-.095-.045-.006-.1-.001-.138.039M8 13.705c-.122.01-.025-.34-.073-.424l-.24-.423c-.014-.026 0-.058.015-.072.014-.012.046-.002.06.02l.23.34c.117-.1.285-.5.37-.43.02.016.021.045.003.073l-.305.477c-.05.079.038.43-.06.439"></path><circle cx="10.258" cy="13.552" r="0.092"></circle><circle cx="4.303" cy="13.555" r="0.091"></circle><path d="m.368 1.168-.126-.001v14.712h27.516V1.139a1022.022 1022.022 0 0 1-16.14.048c-1.67-1.401-4.953-.89-7.02-.87-.845.081-1.923.179-2.487.876zm27.319.054-.006 11.675c-.571-.022-1.974-.007-2.564 0-.016-.095.262-.017.28-.105.019-.134-.259-.018-.308-.076-.096-.192.697.02.714-.525.123-.193-.19-.2-.265-.24-.377-.23-.713-.279-1.112-.495 1.243-.71 1.35-.8 1.361-2.271.89-.325 1.099-1.795-.027-1.916-1.258-.094-1.536 2.12-.126 1.957.036.064.03.12.013.216-1.102.044-.858.036-1.757-.368-.086-.039-.126-.166-.244-.178.056-.097.217-.165.176-.228-.016-.023-.05-.031-.078-.005l-.151.14-.692-.735c.197-.211.609-.349.598-.693-.127.01-.246.025-.332.091l-.478.37-.634-.674a.45.45 0 0 0-.342-.127c.03.123.052.255.131.339l.612.649-1.076.866c-.054-.012-.141-.197-.196-.165-.093.053.085.16.104.23-.051.04-.108.107-.176.122a11.7 11.7 0 0 1-1.863-.98c-.042-.12.59.234.93-.353.38-.58.284-1.516-.514-1.604-1.149-.105-1.379 1.342-.489 1.877a.12.12 0 0 1-.063.099c-.31.141-.58.344-.9.466-.372.142-.765.176-1.146.278-.03.008-.032.042-.031.059.01.13 1.172-.196 1.22-.22l.804-.402c-.191.305-.373 1.059-.464 1.241-.318.682-.868 1.457-1.29 2.08-.206.041-.508.128-.47.372.05.307.607.285.873.32.036.092-.88.049-.944.041-.215-.025-.303-.6-.384-.816-.097-.258-.2-.502-.274-.769-.012-.045-.076-.08-.033-.137.104.194.32.988.595.897a.22.22 0 0 0 .114-.203c-.047-.422-.346-1.592-.734-1.767-.23-.018-.175.382-.15.514-.068.016-.082.102-.116.145-.058.075-.162.115-.127.245.04.146.07.312.162.44.041.058.125.01.204-.007.07.242.175.46.257.695.25 1.115.431.887 1.408.879l-.065.438-2.132.014c-.357-.952-.294-1.894-.184-2.886-.268.854-.185 2.047.112 2.893l-3.405.05c-.05-1.192-.023-2.84-.034-4.044 1.127.01 2.991-.103 3.753-.99.126-.03 1.681-.53 1.353-.667a9 9 0 0 1-1.143-.046c-.447-1.43-2.697-1.164-3.922-1.236l-.002-2.006c0-.037-.055-.058-.081-.057-.344.01-.668.017-1.027-.002.957-.466 1.514-1.736.792-2.652 5.124.011 10.842-.012 15.984-.053Zm-3.446 12.64c.133-.284.445-.684.435-1.016.115-.005.21.001.33.01.048.332.22.586.449.869-.41-.109-.81-.093-1.214.138m1.42.086-.44-.02c-.288-.012-.882.169-1.149.155.56-.319.947-.446 1.59-.135m-3.136-1.053a246 246 0 0 0-4.164.008c-.046-.138-.064-.275-.086-.431.079-.028.25.039.261-.057.003-.029-.018-.058-.055-.059l-.194-.004c-.172-.09.392-.061.681-.215.103-.048.143-.113.165-.22.09-.182-.125-.248-.284-.291l.463-.928-.577-1.141c.126-.397.284-.961.499-1.323.578.375 1.164.662 1.784.94-.057.078-.157.098-.186.179-.02.056.085.182.144.17.095-.018.14-.121.221-.149a.47.47 0 0 0 .254-.213c.064.021.158.21.213.179.016-.01.038-.037.023-.057l-.133-.18 1.108-.862.715.746c-.022.056-.183.139-.15.195.05.086.17-.101.227-.123.145.116.24.282.4.388.07.046.166-.09.185-.157.64.27.556.296 1.275.302-.47.274-1.018.339-1.555.37-.195.013-.286-.288-.493-.24-.283.064-.17.477-.19.69-.066-.045-.024-.134-.093-.16-.087-.025-.065.076-.063.123-.05.006-.142.008-.13.086.019.134.104.536.157.593.021.023.067.013.113.017.11.447.273.948.348 1.408.132.52.78.293 1.171.412l-1.974.013c-.456-.87-.493-1.857-.338-2.795-.337.837-.128 1.917.257 2.786Zm-4.502 1.059-.791.091c.693-.297.812-.291 1.536-.05zm.871.304c.002.094-.146.094-.145 0-.001-.094.147-.094.145 0m-1.566-.395c.43-.576.369-.741.48-1.406l.34-.002c.102.456.146.927.428 1.324-.512-.212-.725-.063-1.248.084m1.702-2.033c-.05.032-.022.085-.041.142-.219.276-1.778.304-2.016.054-.208-.477 1.861-.401 2.057-.196m-1.547-.243c.43-.619.825-1.218 1.179-1.892.018.087.58.986.485 1.064-.15.287-.29.548-.428.85-.4-.07-.789-.052-1.236-.022m.64.718v.025h-.312v-.025zm2.985-3.008c.014.022-.165.183-.165.084.004-.035.124-.148.165-.084m2.273-1.809c.068.119-1.815 1.456-1.876 1.536-.03.023-.07-.038-.068-.07.122-.063 1.83-1.548 1.944-1.466m-.863.464c-.088-.119-.686-.632-.672-.795.168-.008.633.623.757.719.02.039-.061.1-.085.076m.3.157.713.744-.081.079-.715-.744zm.911 1.092c.06-.04.187.063.184.117-.038.085-.138-.072-.184-.117m1.788 3.238c-.377.111-1.16.16-1.515.005-.057-.025-.098-.07-.098-.126-.121-.33 2.439-.49 1.613.12m-1.028-.716c.1.054.176.1.276.18a.5.5 0 0 1-.244.023c-.011-.073-.04-.12-.032-.203m.328.057.346.113a.276.276 0 0 1-.346-.113m.139.954c-.091-.002-.18 0-.263-.013-.012-.002-.012-.057 0-.06.04-.008.349-.052.263.073m-.687-1.363c-.012.03-.108.05-.084.11.02.052.096.058.12.104.059.108.07.242.085.37-.962.134-.673.75.157.699.214.14-.709.068-.77.037a.31.31 0 0 1-.263-.266l-.094-.484c-.06-.31-.206-.59-.23-.914.067.172.256.99.534.61.239-.403.033-1.044-.066-1.518.393-.072 1.135-.096 1.482-.305l.519-.243a3.6 3.6 0 0 1-.216 1.077c-1.647-.201-1.272-.393-1.173.723Zm1.02-.61-.888.554-.124-.68c.343.013.679.04 1.012.125m-1.74-.589c.096.32.295 1.165.044 1.452-.237-.042-.675-2.164-.193-1.73-.201.116.093.14.148.278m-.4.721c-.028-.145-.082-.292-.081-.467.045.14.077.267.082.467m-.149 0c-.036-.127-.09-.258-.082-.422.07.12.073.238.082.423m3.211-3.291c.183.153.25.372.2.617-.092.59-.763 1.146-1.318.776a.67.67 0 0 1-.284-.59c-.048-.735.804-1.37 1.402-.803m-7.45-.72c.364-1.196 2.11-.581 1.321.78-.502.797-1.486-.04-1.321-.78m-2.843 3.295a.7.7 0 0 1 .084.3.8.8 0 0 1-.084-.3m.064.61c-.03.012-.055.022-.076.017-.041-.01-.23-.468-.077-.467zm.046-1.124c.247.15.761 1.527.593 1.761-.199-.08-.793-1.62-.593-1.761M8.807 8.037c-.3-.588.172-1.216.71-1.459 1.036-.66 6.197-.926 6.34.722.353.069.68.055 1.047.074-.367.237-.78.364-1.223.46-.813 1.261-6.046 1.417-6.874.203m3.136 4.941-.195.002-.024-4.048.195-.001zm-.398-1.15c0-.037.121-.03.122.004l.01.986c0 .074-.061.066-.101.06-.085.011-.012-.998-.031-1.05m.028-.096.001-.382h.098l-.001.382zm-.021-.527c.008-.56.017-1.713.014-2.268.038-.01.062-.012.086.004l.022 2.247c.022.133-.132.133-.122.017Zm-.076 1.646c-.116.023-.174-.046-.226-.138-.315-.553-.987-.82-1.643-.902-.002-.586-.024-1.657-.006-2.23.002-.082-.045-.167.016-.243.086.18-.112.431.317.322l-.015-.8c-.192-.045-.225-.058-.311.1a1.3 1.3 0 0 1-.004-.29c.595.172 1.263.225 1.887.259.043 1.162-.014 2.76-.014 3.922Zm.011.094c-.05.018-.119.027-.15-.034.05-.018.078.008.15.034m-3.153-1.108c.073-.264-.371-.705-.583-.818l-.003-.524c.63.326 1.414.746 1.76 1.393.796.094 1.763.473 1.814 1.39-.003 1.715-6.51 1.333-7.779 1.163-.768-.1-2.157-.455-1.787-1.471.11-.262.315-.453.57-.584 1.81-.764 4.07-.675 6.008-.549M7.5 4.595h.193l.007 7.098h-.193zm.26 1.182c.74-.363 1.297-.727 1.81-1.396l.553-.133c.409-.098.85 0 1.274-.001-.636.27-1.202.417-1.83.667-.002.268.002 1.293-.027 1.54-1.098.475-1.33 1.834-.01 2.186.065.47-.107.262-.117.504-.004.09.059.153.121.213l.017 1.656-.715.017a7 7 0 0 0-1.092-.633c.01-1.138.02-3.492.016-4.62m3.918-1.587-1.274-.034c.12-.064.235-.105.36-.153l1.173.002c.05.372.033 1.599-.001 1.968-.005.038-.128.038-.15.006l.018-1.738c0-.05-.088-.05-.126-.051m-.057 1.26c.002-.118-.012-.245.007-.356.004-.022.088-.019.088.01l.006.291c-.004.066-.047.101-.1.054m.098.098-.007.46-.123-.002.007-.46zm-.112-.554c-.039-.226-.01-.471-.013-.718.037-.02.08-.016.136 0l.001.7c0 .053-.118.051-.124.018m-.09 1.014-.605.06c-.451.046-.86.164-1.289.35-.018-.418.02-1.035 0-1.461l1.898-.667c.045.426-.009 1.281-.004 1.718M9.659 9.086c.019.06.03.187-.047.203-.095.02-.14-.104-.12-.18.013-.107.132-.132.167-.023m-.116 1.99-.007.683c-.152-.27-.371-.467-.623-.67zm-1.795.049c.21.145.385.318.5.586-.165.043-.329-.014-.506-.01zm-.01-6.531.57-.037c-.106.273-.308.492-.554.676zm2.105 4.571c-.004-.082-.032-.116-.121-.145-.024-.007-.02-.081-.005-.098.024-.026.076-.016.14-.012l.015.696c-.04.014-.112.026-.155 0-.076-.496.134-.268.126-.44m-.081-.06c.053.002.032.087-.009.094-.026.004-.024-.095.009-.094M3.535.553c1.97-.255 6.22-.616 7.856.55.859.647.627 1.966-.2 2.53-.479.364-1.102.528-1.68.672-.48.62-1.03 1.03-1.743 1.351a1.2 1.2 0 0 1-.007-.301c.185-.122.722-.64.633-.887-1.88-.005-6.134.524-6.489-2.03-.157-1.042.663-1.75 1.63-1.885m-3.168.703 1.688.019c-.405.677-.317 1.576.16 2.183C3.4 4.749 5.784 4.568 7.424 4.6l.02 2.207c-.001.52.013 4.464-.013 4.874-1.338-.021-5.328-.152-5.795 1.341l-1.271-.005zm27.32 14.54-27.319-.02-.003-2.675h1.25c-.273 2.122 5.671 1.558 7.03 1.471.937-.157 3.028-.138 2.73-1.553l.286-.03c.029-.002.045.068.085.067l3.705-.051c.105.262.32.757.594.871-.01-.115-.122-.147-.179-.225a2.4 2.4 0 0 1-.34-.65c.517-.012 1.562-.02 2.08-.018-.039.398-.283.732-.559 1.003-.03.024-.081.037-.08.06l.004.1c.003.069-.107.131-.076.217.115.261.525.079.365-.193.617-.126.797-.125 1.431-.046-.14.202.07.408.25.262.098-.092.053-.221-.024-.312-.009-.03.03-.088.008-.12-.355-.252-.446-.55-.545-.971 1.043-.016 3.154-.02 4.193-.004.035.08.255.416.3.394.078-.036-.198-.263-.215-.393l1.877.006c.004.111-.056.196-.105.288-.172.321-.3.61-.595.835-.003.042.028.096.001.119-.167.096-.156.345.052.367.232.018.3-.233.133-.373.56-.05 1.03-.258 1.62-.143-.177.185 0 .43.218.317.115-.07.004-.199.099-.378.013-.035-.05-.07-.088-.104-.327-.232-.597-.533-.721-.93l2.538-.004zM17.17 14.351c-.012.02-.045.03-.084.034-.14.01-.129-.223.09-.12.025.01.007.065-.006.086m6.83.057c.001.113-.176.113-.174 0-.002-.112.175-.112.173 0m1.678-.166c-.001-.1.156-.1.155 0 .001.1-.156.1-.155 0"></path><path d="M14.48 10.89c-.136.747-.206 1.257.262 1.9-.481-.245-.522-1.505-.261-1.9M23.634 13.986c-.217.177-.243.395-.266.668-.112-.256.01-.513.188-.681.027-.026.094 0 .078.013M16.708 13.867c.002.089-.189.113-.123.584-.255-.221.12-.746.123-.584M23.315 14.058a.68.68 0 0 0-.173.428c-.218-.25.37-.666.173-.428M19.28 14.368c0-.167.05-.306-.022-.48.163.097.151.338.022.48M16.46 13.968c.003.056-.088.046-.094.386-.169-.158.084-.518.093-.386M26.633 14.238a1.4 1.4 0 0 0-.162-.377c.15.052.234.221.162.377M26.198 13.887l.041-.046.123.11-.042.046zM7.02 8.095l-1.102.033a2 2 0 0 1-.023-.449l1.101-.033zm-.069-.062c-.014-.127 0-.23-.023-.326l-.964.024c-.014.114.002.21.007.325zM4.532 9.181c-.484.183-.902.038-1.407.134a.6.6 0 0 0 0-.363c-.026-.102.042-.214.028-.32a7 7 0 0 1-.041-.6c-.004-.116-.075-.228-.055-.343.014-.043.138-.05.191-.032.111.04.258-.014.392-.01.177.005.34.052.52.004a.9.9 0 0 1 .381-.01 2.3 2.3 0 0 0 .01.66.8.8 0 0 1-.018.393c-.091.26.086.454-.001.487Zm-.018-.043c-.162-.422.047-.422-.013-.792a3 3 0 0 1-.024-.658.54.54 0 0 0-.27.009c-.19.061-.364.011-.553.008-.172-.003-.348.054-.538-.014-.017.133.045.212.046.32.003.211.02.413.042.62.012.115-.05.23-.03.345.015.088.06.16.013.268.47-.044.857.044 1.327-.106Z"></path><path d="M4.329 7.958c-.06.051-.121.006-.183.027a.36.36 0 0 1-.336-.047c-.111.032-.237.117-.35.071-.044-.022-.07-.113-.157-.083.032-.077.077-.05.118-.044.025.003.035.064.065.077.106.047.223-.078.332-.063.107.015.207.115.328.03.056.022.117-.028.183.032M4.302 8.37c-.099.019-.135-.082-.218-.083-.23-.004-.498.09-.537.058-.03-.025-.098-.06-.071-.115.05.061.113.104.18.067.081-.044.168-.029.253-.048.147-.034.29-.023.393.12M3.946 8.593c.17.082.303-.079.369.097-.093-.07-.188-.008-.272-.024a.3.3 0 0 0-.231.036c-.115.058-.309.027-.316-.13.202.175.235.11.45.02M4.264 8.914c.014.06-.47.075-.543.059-.063-.014-.109-.02-.172.03-.023-.066.04-.072.067-.09.038-.026.098.016.131.02.248.021.286-.048.517-.02ZM19.014 13.865c.145-.147.294.496.07.58.046-.229.087-.422-.07-.58M21.462 10.857c-.114.748-.136 1.238.34 1.886-.45-.211-.604-1.472-.34-1.886M20.837 11.389c-.141.246-.095.472-.003.733-.205-.061-.167-.79.003-.733M13.585 11.333a1.8 1.8 0 0 0 .13 1.155c-.267-.318-.296-.805-.13-1.155M9.553 6.842q.001 0 .007-.005l.008-.005.003-.001h.003l.014.004.014.007q.012.012.018.037l.005.037.004.032.002.043.003.045-.001.023q-.001.019-.004.023-.004.006-.003.013l-.003.02-.007.019-.007.015a.2.2 0 0 1-.027.051l-.004.006q.001.002-.004.008l-.01.015-.006.007-.016.017q-.012.013-.013.012l-.014.011q-.039.03-.077.017l-.028-.015q.001-.003-.004-.007l-.01-.015q-.005-.01-.006-.01-.002 0-.007.01a.3.3 0 0 1-.037.053.1.1 0 0 1-.046.024q-.03.002-.043-.015l-.009-.01-.01-.016-.005-.014-.003-.008a.1.1 0 0 1-.01-.03l-.005-.043a.4.4 0 0 1-.007-.073l-.002-.054a.5.5 0 0 0-.018-.14q0-.013.002-.016 0-.001.002-.002l.006-.004.007-.004q.017-.012.027-.008l.008.011q.007.01.013.022.006.01.004.01l.005.016a3 3 0 0 1 .01.189l.005.047v.011q.003.002.005.023a.1.1 0 0 0 .013.043q.001.002.007 0a.5.5 0 0 0 .052-.085.1.1 0 0 1 .028-.04q.01-.006.022-.007c.012-.001.012 0 .015.004l.007.005q.006.002.007.009v.004q0 .003.003.004c.003.001 0 .002 0 .003a.2.2 0 0 0 .007.04q.006.024.011.028.008.005.021-.004.022-.014.046-.047c.024-.033.026-.041.032-.06l.006-.015.005-.018q.001-.015.002-.019 0-.003.003-.008a.765.765 0 0 0-.012-.177q-.009-.006-.01-.023l.001-.013q.002-.006.005-.007ZM9.9 6.872h.037q.043 0 .054.007.015.006.016.013v.007q0 .004.002.01.004.01-.007.018-.006.002-.007.006-.007.012-.031.004l-.01-.001q-.008 0-.01-.002-.008-.006-.062.003a1 1 0 0 0-.102.025l-.007.002-.004.001q-.005.002-.005.008v.067a.4.4 0 0 1 .097-.007l.022.006q.016.006.018.01 0 0 .003.003l.005.005q.002.002.001.004l.002.002q.003 0 .002.012 0 .01-.004.014-.003.003-.013.008-.013.006-.014.005l-.01-.003a.2.2 0 0 0-.071-.006h-.04l-.001.025-.003.05-.004.055a.4.4 0 0 0 .001.055l.002.003v.002a1 1 0 0 0 .096-.021l.03-.006.028-.007.023-.004.03-.002.013.001.005.001q.01 0 .018.009.005.004.005.018 0 .015-.006.022a.1.1 0 0 1-.026.007.773.773 0 0 0-.151.033q-.006.003-.034.008c-.028.005-.03.005-.038.005a.3.3 0 0 1-.05-.008l-.005-.001-.006-.006-.007-.01v-.016q.001-.012.007-.016.004-.005.004-.015-.003-.026.006-.144.003-.042.003-.103v-.062l-.004-.009-.004-.014q0-.009.011-.024.007-.007.022-.007l.021-.005q.025-.008.04-.011l.016-.005.018-.006.017-.003a.3.3 0 0 0 .051-.008zM10.129 6.727l.01-.004q.003 0 .016.009l.017.011v.008a.04.04 0 0 1-.007.028q-.006.008-.01.018-.007.01-.012.026l-.01.023-.014.036q0 .01-.002.012l-.005.004h-.021q-.024-.003-.027-.011 0-.003-.003-.003-.004 0-.004-.016a.4.4 0 0 1 .036-.087q.021-.046.036-.054ZM10.405 6.846l.02.001a.2.2 0 0 1 .047.01l.008.003.01.003.004.002.005.004q0 0 .004.003l.005.005q.001 0 .007.009c.006.009.004.009.005.01q.003 0 .002.004 0 .001.003.008t.002.01l-.005.033q-.004.005-.006.013l-.006.014-.022.031-.006.008q-.001.003-.01.01a.3.3 0 0 1-.062.046l-.055.028.022.019q.02.017.026.025.003.005.006.005l.019.017q.018.018.021.024l.004.004.001.002.019.025.013.023q0 .003.001.001l.01.014.014.03.006.018q-.001.01-.004.013l-.017.01q-.01.006-.014.005-.015-.004-.019-.008l-.013-.023a.4.4 0 0 0-.05-.078 1 1 0 0 0-.059-.057.4.4 0 0 1-.05-.05l-.003.023v.039q-.003.012-.002.02a.1.1 0 0 0 0 .037l.002.032a.1.1 0 0 1-.008.04l-.006.01-.005.002-.014.001a.04.04 0 0 1-.02-.004q-.008-.003-.011-.016l-.004-.013v-.037l.004-.066q.01-.128.003-.2 0-.009-.002-.019l-.002-.017a.1.1 0 0 1 .001-.029.05.05 0 0 1 .014-.028.1.1 0 0 1 .027-.018.3.3 0 0 1 .114-.028q.024 0 .026-.002Zm-.127.091.003.007q.003.004.002.008l.002.013a.4.4 0 0 1 .006.075v.014l.01-.003.012-.002.011-.002a.286.286 0 0 0 .1-.06q.04-.037.04-.063v-.007l-.008-.004a.1.1 0 0 0-.033-.01h-.044l-.032.003q-.069.012-.069.031ZM10.793 6.872h.037q.042 0 .054.007.014.006.015.013l.001.007.001.01q.005.01-.006.018-.006.002-.007.006-.008.012-.031.004l-.011-.001q-.008 0-.009-.002-.008-.006-.062.003a1 1 0 0 0-.102.025l-.008.002-.004.001q-.005.002-.005.008v.014l.001.023v.03a.4.4 0 0 1 .097-.007l.022.006q.015.006.017.01 0 0 .004.003l.005.005q.002.002.001.004l.002.002q.003 0 .002.012-.001.01-.004.014l-.014.008-.013.005-.01-.003a.2.2 0 0 0-.071-.006h-.04l-.001.025-.003.05-.004.055a.4.4 0 0 0 0 .055q.002 0 .003.003v.002a1 1 0 0 0 .095-.021l.03-.006.03-.007.022-.004.029-.002.014.001.004.001q.01 0 .02.009.003.004.004.018 0 .015-.007.022a.1.1 0 0 1-.025.007.773.773 0 0 0-.151.033q-.007.003-.035.008c-.028.005-.03.005-.037.005a.3.3 0 0 1-.05-.008l-.006-.001-.006-.006-.006-.01v-.016q0-.012.006-.016.004-.005.004-.015-.003-.026.006-.144.003-.042.003-.103v-.062l-.004-.009-.004-.014q0-.009.012-.024.007-.007.022-.007l.021-.005q.025-.008.04-.011l.016-.005.017-.006.018-.003a.3.3 0 0 0 .05-.008zM11.172 6.879h.007q.007-.002.011-.002.012 0 .017.002.006.003.006.01a1 1 0 0 1 .003.078q0 .04.002.086l.002.083a2 2 0 0 0 .009.144q0 .004.002.013l-.001.015q-.004.009-.01.012-.007.003-.025.002-.008 0-.011-.002l-.01-.01-.007-.026a1 1 0 0 1-.008-.132l-.003-.084a1 1 0 0 1-.002-.066v-.073q.002-.048.018-.05ZM11.536 6.833q.015-.014.035-.002.018.009.02.016l-.001.016a.1.1 0 0 0-.01.047 1 1 0 0 0-.004.12q.008.097.002.175a.1.1 0 0 1-.01.044q-.006.007-.01.009l-.018.005a.03.03 0 0 1-.02-.008l-.005-.002-.005-.004-.002-.004-.02-.03q-.018-.027-.025-.035l-.034-.043a1 1 0 0 1-.075-.109l-.013-.02v.024l.003.041.003.054q0 .011.002.037c.002.026 0 .03 0 .038l.003.023q.007.054-.002.065-.003.006-.028.01h-.017q-.01-.006-.01-.016l-.001-.009a.3.3 0 0 1-.009-.095l-.003-.055-.004-.047v-.145q0-.049.007-.056.015-.016.028-.015h.01q.003 0 .01.007l.008.005.004.003.003.008.002.004.002.004a1.666 1.666 0 0 0 .073.13q.037.058.07.094l.016.02.004.005v-.036l-.003-.084a1 1 0 0 1 .004-.138q.007-.039.02-.051ZM11.877 6.835l.06-.003h.026l.006.006.006.006v.017q.001.02-.005.027-.003.003-.016.003-.012 0-.017.002l-.035.003a1 1 0 0 0-.092.013l-.001.005q.003.016 0 .02-.002.006-.001.07a3 3 0 0 0 .004.21.3.3 0 0 1-.005.07q0 .005-.01.008l-.015-.001h-.014q-.006 0-.016-.008a.03.03 0 0 1-.006-.02q.002-.045-.001-.138L11.743 7v-.078l-.023.005-.03.006a.05.05 0 0 1-.047-.011l-.006-.004.001-.014q.002-.018.006-.024.006-.005.02-.007l.06-.011.014-.003.014-.003q.018-.005.062-.012c.044-.007.05-.006.063-.007ZM12.243 6.872h.037q.043 0 .054.007.015.006.016.013v.007q0 .004.002.01.003.01-.007.018-.006.002-.007.006-.008.012-.031.004l-.01-.001q-.008 0-.01-.002-.008-.006-.062.003a1 1 0 0 0-.102.025l-.008.002-.004.001q-.004.002-.004.008v.067a.4.4 0 0 1 .097-.007l.022.006q.015.006.017.01 0 0 .004.003l.005.005q.002.002.001.004l.002.002q.002 0 .002.012 0 .01-.004.014l-.013.008-.014.005-.01-.003a.2.2 0 0 0-.071-.006h-.04l-.001.025-.003.05-.004.055a.4.4 0 0 0 .001.055l.002.003v.002a1 1 0 0 0 .096-.021l.029-.006.03-.007.022-.004.03-.002.013.001.005.001q.009 0 .018.009.005.004.005.018 0 .015-.007.022a.1.1 0 0 1-.025.007.773.773 0 0 0-.151.033q-.006.003-.035.008c-.029.005-.03.005-.037.005a.3.3 0 0 1-.05-.008l-.005-.001-.006-.006-.007-.01v-.016q0-.012.007-.016.004-.005.004-.015-.003-.026.005-.144.003-.042.003-.103v-.062l-.004-.009-.003-.014q0-.009.011-.024.007-.007.022-.007l.021-.005q.025-.008.04-.011l.016-.005.018-.006.017-.003a.3.3 0 0 0 .051-.008zM12.54 6.865a.2.2 0 0 1 .059.004l.039.011.035.013q.01.004.017.008l.013.006q.014.004.015.014.003.01-.005.023c-.008.013-.008.015-.01.016q-.01.005-.016 0l-.023-.007-.048-.016-.039-.011h-.026a.1.1 0 0 0-.022.006l-.015.012-.011.011q0 .003-.006.01-.014.02-.014.025v.003l-.01.023q-.006.018-.007.025l-.003.02a.2.2 0 0 0-.001.038q0 .015.004.037l.005.026q0 .01.01.028a.1.1 0 0 0 .024.031.1.1 0 0 0 .06.028q.014 0 .023-.002a.1.1 0 0 0 .045-.034.15.15 0 0 0 .042-.094q0-.003-.025-.005l-.025.001-.033.002h-.019l-.008-.007-.004-.008-.002-.015q0-.012.002-.017.003-.005.007-.005.002 0 .002-.002 0-.003.029-.006l.047-.003q.034 0 .04.005l.01.003.01.004.005.004.008.004q.003 0 .005.004l.003.007.002.003q.005.001.006.028a.2.2 0 0 1-.01.064l-.007.017-.006.01-.01.017q-.007.007-.007.01t-.027.031q-.027.027-.031.026-.002-.001-.01.004l-.01.007-.007.002-.018.004a.13.13 0 0 1-.08-.012l-.01-.004-.012-.006-.01-.006a.2.2 0 0 1-.043-.044l-.004-.005-.005-.012-.004-.005q-.008-.008-.014-.044l-.003-.012-.003-.01V7.14l-.003-.016a.2.2 0 0 1 0-.043l.001-.02.004-.03q.001-.012.004-.012l.001-.002.003-.012.004-.012a.2.2 0 0 1 .022-.046.2.2 0 0 1 .03-.043.2.2 0 0 1 .03-.021.1.1 0 0 1 .024-.013q.003 0 .005-.002.002-.003.011-.003ZM12.968 6.846l.02.001a.2.2 0 0 1 .046.01l.009.003.009.003q.001 0 .005.002l.005.004q0 0 .003.003l.005.005q.002 0 .007.009l.006.01.001.004.004.008q.003.007.002.01l-.006.033q-.004.005-.006.013l-.006.014-.021.031-.006.008-.01.01a.3.3 0 0 1-.062.046l-.055.028.021.019q.021.017.027.025.003.005.006.005l.018.017q.018.018.022.024l.004.004v.002q.006.006.02.025c.013.02.013.021.013.023q0 .003.001.001.001 0 .009.014c.008.014.01.02.014.03l.006.018q0 .01-.004.013l-.016.01q-.01.006-.015.005-.015-.004-.018-.008l-.013-.023a.4.4 0 0 0-.05-.078 1 1 0 0 0-.06-.057.4.4 0 0 1-.05-.05l-.002.023v.016l-.001.023-.001.02a.1.1 0 0 0-.001.037l.003.032a.1.1 0 0 1-.008.04l-.006.01-.005.002h-.001l-.014.001a.04.04 0 0 1-.02-.004q-.007-.003-.01-.016l-.005-.013.001-.037.003-.066q.012-.128.004-.2l-.002-.019-.002-.017a.1.1 0 0 1 .001-.029.05.05 0 0 1 .014-.028.1.1 0 0 1 .027-.018.3.3 0 0 1 .113-.028q.026 0 .027-.002Zm-.127.091q0 .003.003.007.003.005.002.008-.001.005.002.013a.4.4 0 0 1 .006.075v.014l.01-.003.011-.002.012-.002a.286.286 0 0 0 .1-.06q.04-.037.04-.063v-.007l-.008-.004a.1.1 0 0 0-.034-.01h-.043l-.033.003q-.069.012-.068.031ZM13.296 6.851a.1.1 0 0 1 .03 0q.018.003.025.008l.006.003.015.012.018.019.018.03.004.01.004.009q.005.013.014.055c.009.042.01.051.012.07l.003.028a1 1 0 0 1 .002.146q-.001.029-.006.033l-.003.002v.003a.02.02 0 0 1-.021.012q-.005 0-.02-.008c-.016-.008-.015-.01-.016-.014s-.001-.013.002-.03a1 1 0 0 0 0-.088v-.019a1 1 0 0 0-.16-.003h-.003l-.009.036-.004.026q-.001.02-.002.022l-.005.045a.1.1 0 0 1-.005.032q0 .008-.008.012-.006.003-.023.003c-.017 0-.019-.002-.02-.004q-.005-.005-.005-.02a.837.837 0 0 1 .027-.22l.004-.013q0-.01.014-.045a.4.4 0 0 1 .067-.127q.023-.022.045-.025m.031.068q-.015-.01-.03.001a.2.2 0 0 0-.041.072l-.014.033-.002.01q0 .007-.003.012l-.004.014.031.002.064.003h.034l.014.002-.005-.034-.006-.032q-.005-.008-.008-.03v-.007l-.005-.006-.003-.007q-.01-.025-.022-.032ZM13.735 6.835l.06-.003h.026l.006.006.006.006.001.017q.002.02-.006.027-.003.003-.015.003t-.018.002l-.034.003a1 1 0 0 0-.093.013l-.001.005q.003.016.001.02-.002.006-.002.07a3 3 0 0 0 .004.21.3.3 0 0 1-.005.07q0 .005-.01.008l-.014-.001h-.014q-.007 0-.017-.008a.03.03 0 0 1-.006-.02v-.138L13.6 7v-.078l-.023.005-.03.006a.05.05 0 0 1-.046-.011l-.006-.004v-.014q.003-.018.007-.024.005-.005.02-.007l.059-.011.014-.003.014-.003q.019-.005.063-.012c.044-.007.05-.006.062-.007ZM13.9 6.879h.006q.007-.002.012-.002.012 0 .017.002.005.003.005.01a1 1 0 0 1 .003.078q0 .04.002.086l.002.083a2 2 0 0 0 .01.144l.001.013v.015q-.006.009-.01.012-.007.003-.025.002-.009 0-.012-.002l-.01-.01-.006-.026a1 1 0 0 1-.008-.132l-.003-.084a1 1 0 0 1-.002-.066l-.001-.073q.003-.048.019-.05ZM14.264 6.833q.015-.014.035-.002.018.009.02.016 0 .012-.002.016a.1.1 0 0 0-.01.047 1 1 0 0 0-.003.12q.008.097.002.175a.1.1 0 0 1-.01.044l-.01.009-.018.005a.03.03 0 0 1-.02-.008l-.006-.002-.005-.004-.002-.004-.02-.03-.024-.035-.035-.043a1 1 0 0 1-.075-.109l-.013-.02.001.024.002.041.003.054.002.037.001.038.002.023q.006.054-.002.065-.002.006-.027.01h-.018q-.01-.006-.01-.016v-.009a.3.3 0 0 1-.01-.095l-.002-.055-.004-.047-.001-.145q0-.049.008-.056.015-.016.028-.015h.01q.003 0 .01.007l.008.005.003.003.003.008.002.004.002.004a1.666 1.666 0 0 0 .073.13q.038.058.07.094l.016.02.004.005v-.036q0-.006-.003-.084a1 1 0 0 1 .004-.138q.008-.039.02-.051ZM14.506 6.865a.2.2 0 0 1 .059.004l.039.011.035.013q.01.004.017.008l.013.006q.014.004.015.014.003.01-.005.023c-.008.013-.008.015-.01.016q-.01.005-.016 0l-.023-.007-.048-.016-.039-.011h-.026a.1.1 0 0 0-.022.006l-.015.012-.011.011q0 .003-.006.01-.014.02-.014.025v.003l-.01.023q-.007.018-.007.025l-.003.02a.2.2 0 0 0-.001.038q0 .015.004.037l.005.026q0 .01.01.028a.1.1 0 0 0 .024.031.1.1 0 0 0 .06.028q.014 0 .023-.002a.1.1 0 0 0 .045-.034.15.15 0 0 0 .042-.094q0-.003-.025-.005l-.025.001-.033.002h-.019l-.008-.007-.004-.008-.002-.015q0-.012.002-.017.003-.005.007-.005.002 0 .002-.002 0-.003.028-.006l.048-.003q.034 0 .04.005l.01.003q.007.002.009.004l.006.004.008.004q.002 0 .005.004l.003.007.002.003q.003.001.006.028a.2.2 0 0 1-.01.064l-.007.017-.006.01-.01.017q-.007.007-.007.01t-.027.031q-.027.027-.031.026-.002-.001-.011.004l-.01.007-.007.002-.017.004a.13.13 0 0 1-.08-.012l-.011-.004-.01-.006-.01-.006a.2.2 0 0 1-.044-.044l-.004-.005-.005-.012-.004-.005q-.008-.008-.014-.044l-.003-.012-.003-.01V7.14l-.003-.016a.2.2 0 0 1 0-.043l.001-.02.004-.03q.001-.012.004-.012l.001-.002.003-.012.004-.012a.2.2 0 0 1 .021-.046.2.2 0 0 1 .032-.043l.029-.021a.1.1 0 0 1 .024-.013q.003 0 .005-.002.002-.003.01-.003ZM15.092 6.865a.2.2 0 0 1 .058.004l.04.011.035.013.017.008.013.006q.014.004.015.014.003.01-.005.023c-.008.013-.008.015-.01.016q-.01.005-.016 0l-.023-.007-.048-.016-.04-.011h-.026a.1.1 0 0 0-.021.006l-.016.012-.01.011q0 .003-.006.01-.014.02-.014.025v.003l-.01.023q-.008.018-.008.025l-.002.02a.2.2 0 0 0-.001.038q0 .015.004.037l.004.026q0 .01.01.028a.1.1 0 0 0 .025.031.1.1 0 0 0 .06.028q.014 0 .023-.002a.1.1 0 0 0 .044-.034.15.15 0 0 0 .043-.094q0-.003-.025-.005l-.025.001-.033.002h-.02l-.007-.007-.004-.008-.002-.015q0-.012.002-.017.003-.005.007-.005.002 0 .002-.002 0-.003.028-.006l.048-.003q.033 0 .04.005l.01.003q.007.002.009.004l.006.004.008.004q.003 0 .005.004l.002.007.002.003q.004.001.007.028a.2.2 0 0 1-.01.064l-.007.017-.006.01-.011.017q-.006.007-.006.01t-.027.031q-.027.027-.031.026-.002-.001-.011.004l-.01.007-.007.002-.017.004a.13.13 0 0 1-.08-.012l-.011-.004-.01-.006-.01-.006a.2.2 0 0 1-.045-.044l-.003-.005-.005-.012-.004-.005q-.008-.008-.014-.044l-.003-.012-.003-.01V7.14l-.003-.016a.2.2 0 0 1 0-.043l.001-.02.004-.03q.001-.012.004-.012l.001-.002.003-.012.004-.012a.2.2 0 0 1 .021-.046.2.2 0 0 1 .032-.043l.029-.021a.1.1 0 0 1 .024-.013q.003 0 .005-.002.002-.003.01-.003ZM15.468 6.868q.019-.008.048.004l.017.004.019.004.018.009.023.014.004.002.013.01.013.012.005.006a.2.2 0 0 1 .038.065.262.262 0 0 1-.022.191.4.4 0 0 1-.032.056l-.01.012a.2.2 0 0 1-.088.07l-.03.007q-.006.002-.023.001l-.018-.002-.02-.01a.12.12 0 0 1-.055-.057.3.3 0 0 1-.024-.064.2.2 0 0 1-.006-.042l-.004-.025.001-.038.003-.038.004-.016.004-.017q.003-.023.009-.03l.012-.023a.26.26 0 0 1 .078-.096l.01-.004zm.011.059-.002-.002q-.003 0-.016.014l-.02.025a.252.252 0 0 0-.042.195l.003.023a.2.2 0 0 0 .02.06l.014.015.014.013q.016.007.037 0l.006-.002.006-.002h.003a.292.292 0 0 0 .065-.064.3.3 0 0 0 .032-.06.2.2 0 0 0 .015-.085.1.1 0 0 0-.005-.033l-.005-.016q.001-.003-.01-.017l-.016-.022a.1.1 0 0 0-.045-.03q-.018-.006-.025 0-.007.003-.015-.002zM9.206 7.695h.007q.007-.002.012-.002.011 0 .016.002.006.003.006.01a1 1 0 0 1 .003.078q0 .04.002.086l.002.083a2 2 0 0 0 .009.144q0 .004.002.013l-.001.015q-.004.009-.01.012-.008.003-.024.002-.009 0-.012-.002l-.01-.01-.007-.026a1 1 0 0 1-.007-.132l-.003-.084a1 1 0 0 1-.002-.066l-.001-.073q.002-.048.018-.05ZM9.57 7.649q.015-.014.035-.002.019.009.02.016l-.001.016a.1.1 0 0 0-.01.047 1 1 0 0 0-.004.12q.009.097.002.175a.1.1 0 0 1-.01.043q-.006.01-.01.01l-.018.005a.03.03 0 0 1-.02-.008l-.005-.002-.005-.004-.002-.004-.02-.03q-.018-.027-.025-.035l-.034-.043a1 1 0 0 1-.075-.109l-.013-.02.001.024.002.041.003.054q0 .011.002.037c.002.026 0 .03 0 .037l.003.023q.006.056-.002.066-.002.006-.027.01h-.018q-.01-.006-.01-.016v-.009a.3.3 0 0 1-.01-.095l-.003-.055-.003-.047-.001-.145q0-.049.007-.056.016-.017.029-.015h.01l.01.006.007.006.004.003.003.007q.001.004.002.005l.002.004a1.666 1.666 0 0 0 .073.13q.037.058.07.094l.016.02.004.005v-.036l-.003-.084a.7.7 0 0 1 .004-.139q.008-.038.02-.05ZM9.911 7.651l.06-.003h.026l.006.006.006.006v.017q.001.02-.005.027-.003.003-.016.003-.011 0-.017.002l-.035.003a1 1 0 0 0-.092.013l-.001.005q.003.016 0 .02-.002.006-.001.07a3 3 0 0 0 .004.21.3.3 0 0 1-.005.07q0 .005-.01.008l-.015-.001h-.013q-.008 0-.017-.008a.03.03 0 0 1-.006-.02V7.94l-.003-.126v-.078l-.023.005-.03.006a.05.05 0 0 1-.047-.011l-.005-.004v-.014q.002-.018.006-.024.006-.005.021-.007l.059-.011.014-.003.014-.003q.019-.005.062-.012c.043-.007.05-.006.063-.007ZM10.191 7.684q.02-.008.048.004l.018.004.019.004.017.009.024.014.003.002.013.01.014.012.005.006a.2.2 0 0 1 .038.065.262.262 0 0 1-.022.191.4.4 0 0 1-.033.056l-.01.012a.2.2 0 0 1-.088.07l-.029.007-.023.001-.019-.002-.02-.01a.12.12 0 0 1-.054-.057.3.3 0 0 1-.024-.064.2.2 0 0 1-.006-.042l-.004-.025v-.038l.004-.038.004-.017.003-.016q.003-.023.01-.03l.012-.023a.26.26 0 0 1 .077-.096l.01-.005zm.012.059L10.2 7.74q-.003 0-.015.014l-.02.025a.252.252 0 0 0-.042.195l.003.023a.2.2 0 0 0 .02.059l.013.016q.008.009.015.013.015.008.037 0l.006-.002.006-.002h.003a.292.292 0 0 0 .065-.064.3.3 0 0 0 .031-.06.2.2 0 0 0 .016-.085.1.1 0 0 0-.005-.033l-.005-.016q0-.002-.01-.017l-.016-.022a.1.1 0 0 0-.045-.03q-.018-.006-.026 0-.005.003-.014-.002zM10.886 7.692q.006-.006.009-.007h.017q.018 0 .018.005 0 .001.002.002l.006.008q.004.006.004.009l-.008.036-.013.05-.006.018-.005.02-.016.068q-.013.053-.016.076l-.008.046-.01.04v.005l-.004.016a.1.1 0 0 1-.023.04q-.009.01-.012.01h-.002q.001.003-.005.004h-.012l-.016-.003q-.015-.005-.02-.013l-.006-.008a.1.1 0 0 1-.014-.019l-.013-.026q-.001-.006-.004-.01l-.003-.01a.5.5 0 0 1-.026-.093q-.003-.002-.008-.025l-.005-.026-.006-.018-.006-.016-.005-.015-.004-.015-.003-.008q-.002-.003-.006-.017l-.004-.015-.004-.012q0-.009.003-.012t.013-.01l.014-.007h.011l.014.022.015.023q-.001.002.004.01l.003.011.011.038.01.036q.001.008.008.024l.007.027q.005.033.024.083l.01.026.01-.036V8.02l.002-.009.001-.008a.1.1 0 0 1 .01-.043q-.001-.01.004-.026l.005-.022.01-.047.011-.044.005-.018.02-.072zM11.006 7.695h.007q.007-.002.011-.002.012 0 .017.002.006.003.006.01a1 1 0 0 1 .003.078q0 .04.002.086l.002.083a2 2 0 0 0 .009.144q0 .004.002.013l-.001.015q-.004.009-.01.012-.007.003-.025.002-.008 0-.011-.002l-.01-.01L11 8.1a1 1 0 0 1-.008-.132l-.003-.084a1 1 0 0 1-.002-.066v-.073q.001-.048.018-.05ZM11.13 8.041l-.002-.003-.002-.004-.004-.008q-.014-.021.002-.036.01-.01.017-.01.005 0 .016.01l.038.04a.3.3 0 0 0 .035.036.1.1 0 0 0 .029.016.1.1 0 0 0 .025.004.1.1 0 0 0 .025-.005.1.1 0 0 0 .027-.024q.022-.025.03-.042c.007-.017.006-.03.007-.057q0-.037-.02-.058l-.017-.012-.019-.002a.4.4 0 0 0-.101.02q-.04.014-.054.008l-.01-.003-.011-.006a.1.1 0 0 1-.02-.027l-.003-.007q-.001 0-.005-.019a.04.04 0 0 1 0-.02l.001-.019q0-.005.004-.016l.007-.015.007-.013.008-.015a.2.2 0 0 1 .09-.07l.015-.004.015-.004.022-.002h.02q0 .003.005.003.014 0 .045.015.026.015.027.02l.002.004.003.005q0 .007.007.01.006.004-.006.025-.006.008-.018.004l-.01-.002h-.004q0-.003-.003-.002l-.028-.011a.1.1 0 0 0-.05-.009.1.1 0 0 0-.054.025.2.2 0 0 0-.04.047.1.1 0 0 0-.003.025q0 .02.005.021l.003-.001.015-.005.018-.005.03-.008a.3.3 0 0 1 .076-.01h.023l.02.01q.046.026.057.059a.2.2 0 0 1 .007.12.2.2 0 0 1-.062.1.1.1 0 0 1-.08.033h-.019a.1.1 0 0 1-.042-.012.2.2 0 0 1-.095-.094ZM11.717 7.675h.022q.005 0 .015.011c.01.011.01.013.01.018l.007.021v.003l.001.005.002.006a.5.5 0 0 1 .021.116q.002.003.002.026v.04a.3.3 0 0 1-.009.057l-.004.012a.3.3 0 0 1-.03.06.4.4 0 0 1-.04.055l-.015.014q-.003.007-.016.016l-.014.01a.1.1 0 0 0-.022.011l-.018.008q-.014.003-.028.002a.1.1 0 0 1-.06-.025l-.013-.014-.008-.012v-.002l-.004-.006-.004-.008a.3.3 0 0 1-.026-.086 1 1 0 0 1 .008-.227q.002-.003.002-.012l.002-.014.001-.01.008-.026a.05.05 0 0 1 .023-.027l.016.008.016.01q.004.003.003.007-.003.003-.002.01a.2.2 0 0 1-.01.048l-.003.036a1 1 0 0 0-.006.12q0 .053.01.105l.01.027a.1.1 0 0 0 .015.024q.027.033.08-.02a.3.3 0 0 0 .034-.041.2.2 0 0 0 .04-.092.673.673 0 0 0-.023-.203q-.008 0-.012-.017a.05.05 0 0 1 0-.03q.003-.012.013-.012zM12.002 7.667a.1.1 0 0 1 .03 0q.018.002.025.008l.007.003.014.012.018.019.018.03.004.01.004.009q.005.013.014.055c.009.042.01.051.013.07l.002.028a1 1 0 0 1 .002.146q0 .029-.006.033l-.002.002-.001.003a.02.02 0 0 1-.02.012q-.008 0-.021-.008c-.013-.008-.015-.01-.016-.014s-.001-.013.002-.03a1 1 0 0 0 .001-.088l-.001-.019a1 1 0 0 0-.16-.003h-.003l-.009.036-.004.026q-.001.02-.002.022l-.005.045a.1.1 0 0 1-.005.031q0 .009-.007.013-.007.003-.024.003c-.017 0-.018-.002-.02-.004q-.005-.005-.005-.02a.837.837 0 0 1 .027-.22l.004-.013q0-.011.014-.045a.4.4 0 0 1 .067-.127q.023-.023.045-.025m.031.068q-.015-.01-.03.001a.2.2 0 0 0-.041.072l-.014.033-.002.01q0 .008-.003.012l-.004.014.032.002.063.003h.034l.014.002q.001-.001-.005-.034l-.006-.032q-.006-.008-.008-.03V7.78l-.004-.006-.004-.007q-.01-.025-.022-.032ZM12.223 7.706q.006-.005.025-.005.018 0 .02.004.006.005.007.044v.065q-.002.042-.006.061l-.004.097a.25.25 0 0 0 .008.105q.004.006.01.007.01.002.04-.005c.03-.007.036-.01.048-.016a.2.2 0 0 1 .046-.012l.02-.004.018-.003.02.001q.025.005.027.008 0 .003.002.003.004 0 .008.015 0 .005-.006.02t-.01.015a.1.1 0 0 1-.022 0 .3.3 0 0 0-.093.018l-.027.008-.026.008a.2.2 0 0 1-.053.006l-.017-.005-.016-.009-.01-.01q-.017-.015-.025-.052a.6.6 0 0 1-.001-.153l.002-.04zM12.781 8.041l-.003-.003-.002-.004q.001-.002-.004-.008-.012-.021.002-.036.01-.01.017-.01.005 0 .017.01l.038.04a.3.3 0 0 0 .034.036.1.1 0 0 0 .03.016.1.1 0 0 0 .025.004.1.1 0 0 0 .024-.005.1.1 0 0 0 .027-.024q.023-.025.03-.042c.007-.017.006-.03.007-.057q0-.037-.02-.058l-.017-.012-.018-.002a.4.4 0 0 0-.102.02q-.04.014-.054.008l-.01-.003-.011-.006a.1.1 0 0 1-.02-.027l-.003-.007-.004-.019a.04.04 0 0 1-.001-.02l.002-.019q-.001-.005.004-.016l.006-.015.007-.013.008-.015a.2.2 0 0 1 .09-.07l.015-.004.015-.004.023-.002h.019q.001.003.005.003.014 0 .045.015.026.015.027.02l.002.004.003.005q.001.007.007.01.008.004-.006.025-.006.008-.018.004l-.01-.002h-.003q-.002-.003-.003-.002a.1.1 0 0 1-.029-.011.1.1 0 0 0-.05-.009.1.1 0 0 0-.054.025.2.2 0 0 0-.04.047.1.1 0 0 0-.003.025q0 .02.005.021l.004-.001.014-.005.018-.005.031-.008a.3.3 0 0 1 .075-.01h.024l.02.01q.045.026.056.059a.2.2 0 0 1 .008.12.2.2 0 0 1-.063.1.1.1 0 0 1-.08.033h-.018a.1.1 0 0 1-.042-.012.2.2 0 0 1-.096-.094ZM13.372 7.651l.06-.003h.026l.006.006.006.006v.017q.001.02-.005.027-.003.003-.016.003-.011 0-.017.002l-.035.003a1 1 0 0 0-.092.013l-.001.005q.003.016 0 .02-.002.006-.001.07a3 3 0 0 0 .004.21.3.3 0 0 1-.005.07q0 .005-.01.008l-.015-.001h-.013q-.008 0-.017-.008a.03.03 0 0 1-.006-.02V7.94l-.003-.126v-.078l-.023.005-.03.006a.05.05 0 0 1-.047-.011l-.005-.004v-.014q.002-.018.006-.024.006-.005.021-.007l.059-.011.014-.003.014-.003q.019-.005.062-.012c.043-.007.05-.006.063-.007ZM13.752 7.675h.023q.003 0 .014.011c.011.011.01.013.01.018l.007.021v.003l.002.005q0 .003.002.006a.5.5 0 0 1 .02.116q.002.003.002.026v.04a.3.3 0 0 1-.008.057l-.004.012a.3.3 0 0 1-.03.06.4.4 0 0 1-.042.055l-.013.014q-.005.007-.017.016l-.014.01a.1.1 0 0 0-.022.011l-.018.008q-.013.003-.028.002a.1.1 0 0 1-.06-.025l-.012-.014-.01-.012v-.002l-.003-.006-.004-.008a.3.3 0 0 1-.025-.086 1 1 0 0 1 .007-.227q.002-.003.002-.012l.002-.014.001-.01.008-.026a.05.05 0 0 1 .023-.027l.016.008.016.01q.004.003.003.007-.002.003-.002.01a.2.2 0 0 1-.009.048l-.004.036a1 1 0 0 0-.006.12q0 .053.01.105l.01.027a.1.1 0 0 0 .015.024q.027.033.08-.02a.3.3 0 0 0 .035-.041.2.2 0 0 0 .039-.092.673.673 0 0 0-.023-.203q-.008 0-.011-.017a.05.05 0 0 1 0-.03q.003-.012.012-.012zM14.153 7.729l.008.007.009.007.004.004.005.004.006.008q.011.014.022.035l.015.031q0 .003.002.008c.002.005 0 .008.002.014l.003.012q.002.003 0 .005l-.001.01-.001.012a.3.3 0 0 1-.012.05q-.002.005-.003.01l-.002.004q0 .004-.01.02l-.01.016-.001.001-.003.005q-.003.005-.002.006l-.016.017-.026.026a.3.3 0 0 1-.064.042l-.017.01q-.005.006-.042.017a.2.2 0 0 1-.064.012.1.1 0 0 1-.04 0l-.021-.008-.006-.005-.002-.005q-.002 0-.004-.005a.325.325 0 0 1 0-.067V8q.002-.015.006-.109.004-.093.004-.144v-.007l-.001-.008q0-.015.017-.037l.008-.01q.003-.003.007-.003.006 0 .01-.004l.029-.007h.027a.2.2 0 0 1 .09.018l.017.007.021.011q.016.01.018.01l.009.007zm-.1.012a.2.2 0 0 0-.048-.014.1.1 0 0 0-.046-.002l-.01.003-.004.002v.003l.002.005.001.007.002.026q.003.023-.002.163a1 1 0 0 1-.007.117q-.003.01.004.01a.3.3 0 0 0 .133-.049.24.24 0 0 0 .072-.082.2.2 0 0 0 .015-.057.1.1 0 0 0-.01-.047l-.007-.011-.01-.013-.01-.01q-.002-.003-.012-.011l-.01-.01q-.028-.022-.033-.022zM14.294 7.695h.007q.007-.002.011-.002.012 0 .017.002.006.003.006.01a1 1 0 0 1 .003.078q0 .04.002.086l.002.083a2 2 0 0 0 .009.144q0 .004.002.013l-.001.015q-.004.009-.01.012-.007.003-.025.002-.008 0-.011-.002l-.01-.01-.007-.026a1 1 0 0 1-.008-.132l-.003-.084a1 1 0 0 1-.002-.066v-.073q.002-.048.018-.05ZM14.533 7.684q.02-.008.048.004l.018.004.018.004.018.009.023.014.004.002.013.01.014.012.005.006a.2.2 0 0 1 .038.065.262.262 0 0 1-.022.191.4.4 0 0 1-.033.056l-.01.012a.2.2 0 0 1-.088.07l-.03.007-.022.001-.02-.002-.019-.01a.12.12 0 0 1-.054-.057.3.3 0 0 1-.025-.064.2.2 0 0 1-.006-.042l-.003-.025v-.038l.003-.038.004-.017.004-.016q.003-.023.009-.03l.013-.023a.26.26 0 0 1 .077-.096l.01-.005q.008-.001.013-.004Zm.012.059-.003-.002q-.003 0-.016.014l-.02.025a.252.252 0 0 0-.042.195q.001.003.004.023a.2.2 0 0 0 .02.059l.013.016q.008.009.015.013.016.008.037 0l.006-.002.006-.002h.002a.292.292 0 0 0 .065-.064.3.3 0 0 0 .032-.06.2.2 0 0 0 .016-.085.1.1 0 0 0-.005-.033l-.005-.016q0-.002-.01-.017l-.017-.022a.1.1 0 0 0-.044-.03q-.019-.006-.026 0-.006.003-.014-.002zM14.855 8.071l.008.01q.007.01.01.01l.006.007q.007.007.01.028l-.001.01-.008.013-.008.008q-.014.017-.018.017l-.007.004q-.003.003-.017.003a.03.03 0 0 1-.018-.004l-.007-.005q-.008 0-.014-.022a.06.06 0 0 1 .003-.045.1.1 0 0 1 .026-.03q.012-.01.022-.01c.01 0 .009 0 .01.003q.001.003.002.003Zm-.024-.393q.016-.005.022-.002.008.004.015.025l.009.037.001.07v.154q0 .019-.01.024l-.004.004q0 .007-.012.009a.04.04 0 0 1-.018-.006l-.017-.01a.4.4 0 0 1-.004-.086 1 1 0 0 0-.003-.162l-.002-.019q-.005-.02-.001-.026.003-.005.024-.012Z"></path></svg>
<hr>
<!-- -->
<section data-footnotes="true" class="footnotes"><h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI sr-only" id="footnote-label">Footnotes<a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#footnote-label" class="hash-link" aria-label="Direct link to Footnotes" title="Direct link to Footnotes" translate="no">​</a></h2>
<ol>
<li class="anchorTargetHideOnScrollNavbar_vjPI" id="user-content-fn-1-28929d">
<p>Apparently, the term was first introduced <a href="https://projects.csail.mit.edu/gsb/old-archive/gsb-archive/gsb2000-02-11.html" target="_blank" rel="noopener noreferrer" class="">by Carlin J. Vieri from MIT</a> in the 2000s. <a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#user-content-fnref-1-28929d" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li class="anchorTargetHideOnScrollNavbar_vjPI" id="user-content-fn-2-28929d">
<p>Hope this analogy doesn’t sound too awkward for real drivers. I’m more of a bicycle person. <a href="https://blog.axiorema.com/engineering/dont-shave-that-yak-go-in-visual-studio/#user-content-fnref-2-28929d" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
            <category>extension</category>
            <category>go</category>
            <category>visual-studio</category>
            <category>visualdock-server</category>
            <category>vsix</category>
        </item>
        <item>
            <title><![CDATA[Quickly restoring 1M+ files from backup]]></title>
            <link>https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/</link>
            <guid>https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/</guid>
            <pubDate>Thu, 25 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[To make restoring from a backup both quick and durable, you might need to step into undocumented territory.]]></description>
            <content:encoded><![CDATA[<p>How does one implement restoring a file from a backup on Windows? Well, you start from
<code>CreateFile</code>, then use <code>WriteFile</code> to reassemble its content, and finally <code>CloseHandle</code><sup><a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#user-content-fn-1-afc97a" id="user-content-fnref-1-afc97a" data-footnote-ref="true" aria-describedby="footnote-label" class="anchorTargetHideOnScrollNavbar_vjPI">1</a></sup>.</p>
<p>Oh, the restore operation needs to be <strong>durable</strong>?</p>
<p>I guess we’ll need to call <code>FlushFileBuffers</code> before closing the file. Or perhaps even use
<code>FILE_FLAG_WRITE_THROUGH</code> so all our write operations go straight to disk. Flushing and
writing through aren’t cheap, but we’re still talking about a single file.</p>
<p>…</p>
<p>Did you just say a <em>million</em> files?</p>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="part-1-denial">Part 1: Denial<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#part-1-denial" class="hash-link" aria-label="Direct link to Part 1: Denial" title="Direct link to Part 1: Denial" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="a-million-files-sounds-inadequate-right">A million files sounds inadequate, right?<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#a-million-files-sounds-inadequate-right" class="hash-link" aria-label="Direct link to A million files sounds inadequate, right?" title="Direct link to A million files sounds inadequate, right?" translate="no">​</a></h3>
<p>It might be reasonable to assume you won’t regularly have a million or more files
in one location on Windows. That many files quickly becomes a burden for both the filesystem
and the administrator when they have to perform maintenance tasks. Native Windows applications
usually design their storage in ways that rarely produce millions of files<sup><a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#user-content-fn-2-afc97a" id="user-content-fnref-2-afc97a" data-footnote-ref="true" aria-describedby="footnote-label" class="anchorTargetHideOnScrollNavbar_vjPI">2</a></sup>.</p>
<p>Unfortunately, this doesn’t pass the reality check.</p>
<p>We were planning a backup feature for VisualSVN Server that had to be fully compatible with
all existing Subversion repository formats. Older repository formats did not support <em>packing</em>
that reduces the number of files on disk by repacking individual revision files together.
So for a repository with a million commits you would have roughly 2 million files on disk.</p>
<div class="theme-admonition theme-admonition-info admonition_Gfwi alert alert--info"><div class="admonitionContent_UjKb"><p>Also, packing a repository is a regular background operation that an administrator
may opt out from. It’s not something we have control over, and we absolutely had
to be ready to deal with “a couple million files”.</p></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="is-there-a-reason-to-make-restores-durable">Is there a reason to make restores durable?<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#is-there-a-reason-to-make-restores-durable" class="hash-link" aria-label="Direct link to Is there a reason to make restores durable?" title="Direct link to Is there a reason to make restores durable?" translate="no">​</a></h3>
<p>In other words, why even bother with restore durability?</p>
<p>The problem is that a non-durable restore is like an uncommitted transaction. You created
some directories, wrote some files and indicated that your operation is complete. Then your
server has a hard restart, and suddenly some of those directories are missing file entries
and some of those files have zeroes in them or wrong metadata.</p>
<p>So before you indicate success and leave the scope of your operation, you have to go
the extra mile to ensure that the data you wrote actually hit the disk — and will
remain consistent in the event of a hard reboot or a BSOD.</p>
<p>How does one do that? By making things slower and flushing to disk.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="part-2-anger">Part 2: Anger<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#part-2-anger" class="hash-link" aria-label="Direct link to Part 2: Anger" title="Direct link to Part 2: Anger" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="flushing-to-disk-cant-be-that-slow">Flushing to disk can’t be that slow!<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#flushing-to-disk-cant-be-that-slow" class="hash-link" aria-label="Direct link to Flushing to disk can’t be that slow!" title="Direct link to Flushing to disk can’t be that slow!" translate="no">​</a></h3>
<p>Actually, it is <em>ridiculously</em> slow, even on modern hardware.</p>
<p>When you call an API to write something to disk, the OS copies the data and will
happily confirm the write request without waiting for the data to reach the disk.
This improves latency and throughput.</p>
<p>But if you want to guarantee that the written data has reached the disk, you can
ask the OS to <a href="https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-flushfilebuffers" target="_blank" rel="noopener noreferrer" class=""><code>FlushFileBuffers</code></a>.
This breaks the entire asynchronous pipeline and causes the OS to block until
the data is written to disk and hardware flushed.</p>
<p>Those costs stack up quickly if you have to do that for every file. For writing
a million files, expect a <strong>5-10× slowdown</strong> in wall-clock time. It does get
worse with HDDs.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="if-we-were-on-linux-all-that-surely-would-be-much-faster">If we were on Linux, all that surely would be much faster<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#if-we-were-on-linux-all-that-surely-would-be-much-faster" class="hash-link" aria-label="Direct link to If we were on Linux, all that surely would be much faster" title="Direct link to If we were on Linux, all that surely would be much faster" translate="no">​</a></h3>
<p>No, not really.</p>
<p>Unix I/O calls are generally faster due to reasons like not having tens of
filesystem filters. But there is no silver bullet when it comes to flushing to
disk, because you actually need to go all the way and make sure that the data
is physically on the device.</p>
<p>There is some variety in things like <code>fsync</code>, <code>fdatasync</code>, <code>F_FULLFSYNC</code>,
<code>F_BARRIERFSYNC</code>, so you actually may make your app faster by persisting less.
But if we’re talking about similar guarantee levels, then the overall
speed is pretty much the same.</p>
<div class="theme-admonition theme-admonition-tip admonition_Gfwi alert alert--success"><div class="admonitionContent_UjKb"><p>It’s trickier to perform an <code>fdatasync</code> on Windows, but
there you also have <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntflushbuffersfileex" target="_blank" rel="noopener noreferrer" class=""><code>NtFlushBuffersFileEx</code></a>
and <code>FLUSH_FLAGS_FILE_DATA_SYNC_ONLY</code>.</p></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="part-3-bargaining">Part 3: Bargaining<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#part-3-bargaining" class="hash-link" aria-label="Direct link to Part 3: Bargaining" title="Direct link to Part 3: Bargaining" translate="no">​</a></h2>
<p>So, apparently both the speed and durability are equally important for restoring
a repository from backup.</p>
<p>You don’t want a restore to take hours, since that is going to hinder your
disaster recovery strategy. But neither do you want to risk having a repository
with a hidden corruption if you remotely called <code>Restore-SvnRepository</code> in
PowerShell and didn’t notice that the VM got abruptly powered off.</p>
<p>How do we approach this problem if we want to retain both speed and durability?</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="maybe-we-write-through">Maybe we write through?<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#maybe-we-write-through" class="hash-link" aria-label="Direct link to Maybe we write through?" title="Direct link to Maybe we write through?" translate="no">​</a></h3>
<!-- -->
<p>Let’s say instead of calling <code>FlushFileBuffers</code> for every file, we open the files
with <code>FILE_FLAG_WRITE_THROUGH</code>. It could be faster because the OS knows we want the
durable writes for a file and has more opportunities to optimize the actual I/O.</p>
<p>Unfortunately, it doesn’t solve the speed problem for a million files. Even though
we started writing directly to disk, the OS is still forced to complete a physical flush
per every <code>WriteFile</code>. So each file becomes an unavoidable barrier in the terms
of writing to the device. If most of the files are small, writing through
doesn’t really help. <svg width="24" height="24" viewBox="0 0 16 16" style="vertical-align:middle"><defs><linearGradient id="ic_fluent_dismiss_circle_16_color__a" x1="3.875" y1="2.75" x2="13" y2="16" gradientUnits="userSpaceOnUse"><stop stop-color="#E5484D"></stop><stop offset="1" stop-color="#B54548"></stop></linearGradient><linearGradient id="ic_fluent_dismiss_circle_16_color__b" x1="6.01126" y1="8.19887" x2="8.35442" y2="10.6354" gradientUnits="userSpaceOnUse"><stop stop-color="#FDFDFD"></stop><stop offset="1" stop-color="#FECBE6"></stop></linearGradient></defs><path fill="url(#ic_fluent_dismiss_circle_16_color__a)" d="M8 2C11.3137 2 14 4.68629 14 8C14 11.3137 11.3137 14 8 14C4.68629 14 2 11.3137 2 8C2 4.68629 4.68629 2 8 2Z"></path><path fill="url(#ic_fluent_dismiss_circle_16_color__b)" d="M5.89645 5.89645C6.07001 5.72288 6.33944 5.7036 6.53431 5.83859L6.60355 5.89645L8 7.293L9.39645 5.89645C9.57001 5.72288 9.83944 5.7036 10.0343 5.83859L10.1036 5.89645C10.2771 6.07001 10.2964 6.33944 10.1614 6.53431L10.1036 6.60355L8.707 8L10.1036 9.39645C10.2771 9.57001 10.2964 9.83944 10.1614 10.0343L10.1036 10.1036C9.92999 10.2771 9.66056 10.2964 9.46569 10.1614L9.39645 10.1036L8 8.707L6.60355 10.1036C6.42999 10.2771 6.16056 10.2964 5.96569 10.1614L5.89645 10.1036C5.72288 9.92999 5.7036 9.66056 5.83859 9.46569L5.89645 9.39645L7.293 8L5.89645 6.60355C5.72288 6.42999 5.7036 6.16056 5.83859 5.96569L5.89645 5.89645Z"></path></svg></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="maybe-we-restore-multiple-files-at-once">Maybe we restore multiple files at once?<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#maybe-we-restore-multiple-files-at-once" class="hash-link" aria-label="Direct link to Maybe we restore multiple files at once?" title="Direct link to Maybe we restore multiple files at once?" translate="no">​</a></h3>
<!-- -->
<p>Building on the previous idea, we could make most of our I/O asynchronous,
and restore multiple files at once. Theoretically, if we have <code>N</code> outgoing
<code>FlushFileBuffers</code> calls or write-through operations, we can possibly expect
an up to <code>N</code> times speedup.</p>
<p>In practice, the idea doesn’t work: <svg width="24" height="24" viewBox="0 0 16 16" style="vertical-align:middle"><defs><linearGradient id="ic_fluent_dismiss_circle_16_color__a" x1="3.875" y1="2.75" x2="13" y2="16" gradientUnits="userSpaceOnUse"><stop stop-color="#E5484D"></stop><stop offset="1" stop-color="#B54548"></stop></linearGradient><linearGradient id="ic_fluent_dismiss_circle_16_color__b" x1="6.01126" y1="8.19887" x2="8.35442" y2="10.6354" gradientUnits="userSpaceOnUse"><stop stop-color="#FDFDFD"></stop><stop offset="1" stop-color="#FECBE6"></stop></linearGradient></defs><path fill="url(#ic_fluent_dismiss_circle_16_color__a)" d="M8 2C11.3137 2 14 4.68629 14 8C14 11.3137 11.3137 14 8 14C4.68629 14 2 11.3137 2 8C2 4.68629 4.68629 2 8 2Z"></path><path fill="url(#ic_fluent_dismiss_circle_16_color__b)" d="M5.89645 5.89645C6.07001 5.72288 6.33944 5.7036 6.53431 5.83859L6.60355 5.89645L8 7.293L9.39645 5.89645C9.57001 5.72288 9.83944 5.7036 10.0343 5.83859L10.1036 5.89645C10.2771 6.07001 10.2964 6.33944 10.1614 6.53431L10.1036 6.60355L8.707 8L10.1036 9.39645C10.2771 9.57001 10.2964 9.83944 10.1614 10.0343L10.1036 10.1036C9.92999 10.2771 9.66056 10.2964 9.46569 10.1614L9.39645 10.1036L8 8.707L6.60355 10.1036C6.42999 10.2771 6.16056 10.2964 5.96569 10.1614L5.89645 10.1036C5.72288 9.92999 5.7036 9.66056 5.83859 9.46569L5.89645 9.39645L7.293 8L5.89645 6.60355C5.72288 6.42999 5.7036 6.16056 5.83859 5.96569L5.89645 5.89645Z"></path></svg></p>
<ul>
<li class="">The speedup is not so great. Perhaps, because we didn’t entirely
remove flushing, but just queued as many operations as possible and expect
the OS to magically coalesce them.</li>
<li class="">In the actual case, there are both files and directories, which results
in additional dependencies that limit how many operations you can queue.</li>
<li class="">Asynchronously calling <code>FlushFileBuffers</code> is tough.</li>
<li class="">Juggling with a lot of open file handles is also tough and error-prone.</li>
<li class="">That makes the restore code asynchronous, thus far less predictable and more complex.</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="maybe-we-restore-straight-into-a-packed-form">Maybe we restore straight into a packed form?<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#maybe-we-restore-straight-into-a-packed-form" class="hash-link" aria-label="Direct link to Maybe we restore straight into a packed form?" title="Direct link to Maybe we restore straight into a packed form?" translate="no">​</a></h3>
<!-- -->
<p>We could try reassembling content on-the-fly when restoring, so that our million
of files would be restored as a much lower number of packed files. Then flushing
them to disk is no longer a problem.</p>
<p>A nice concept, but it’s impractical for multiple reasons: <svg width="24" height="24" viewBox="0 0 16 16" style="vertical-align:middle"><defs><linearGradient id="ic_fluent_dismiss_circle_16_color__a" x1="3.875" y1="2.75" x2="13" y2="16" gradientUnits="userSpaceOnUse"><stop stop-color="#E5484D"></stop><stop offset="1" stop-color="#B54548"></stop></linearGradient><linearGradient id="ic_fluent_dismiss_circle_16_color__b" x1="6.01126" y1="8.19887" x2="8.35442" y2="10.6354" gradientUnits="userSpaceOnUse"><stop stop-color="#FDFDFD"></stop><stop offset="1" stop-color="#FECBE6"></stop></linearGradient></defs><path fill="url(#ic_fluent_dismiss_circle_16_color__a)" d="M8 2C11.3137 2 14 4.68629 14 8C14 11.3137 11.3137 14 8 14C4.68629 14 2 11.3137 2 8C2 4.68629 4.68629 2 8 2Z"></path><path fill="url(#ic_fluent_dismiss_circle_16_color__b)" d="M5.89645 5.89645C6.07001 5.72288 6.33944 5.7036 6.53431 5.83859L6.60355 5.89645L8 7.293L9.39645 5.89645C9.57001 5.72288 9.83944 5.7036 10.0343 5.83859L10.1036 5.89645C10.2771 6.07001 10.2964 6.33944 10.1614 6.53431L10.1036 6.60355L8.707 8L10.1036 9.39645C10.2771 9.57001 10.2964 9.83944 10.1614 10.0343L10.1036 10.1036C9.92999 10.2771 9.66056 10.2964 9.46569 10.1614L9.39645 10.1036L8 8.707L6.60355 10.1036C6.42999 10.2771 6.16056 10.2964 5.96569 10.1614L5.89645 10.1036C5.72288 9.92999 5.7036 9.66056 5.83859 9.46569L5.89645 9.39645L7.293 8L5.89645 6.60355C5.72288 6.42999 5.7036 6.16056 5.83859 5.96569L5.89645 5.89645Z"></path></svg></p>
<ul>
<li class="">
<p>Restore cannot result in data that is different from what has been
backed up. Otherwise, you’ve just lost the level of protection backup
was supposed to give and turned your performance problem into a much more
high-level problem.</p>
</li>
<li class="">
<p>If for some reason your backup was taken from a corrupted repository, with
repacking it on-the-fly, you may not be able to restore it at all.</p>
</li>
<li class="">
<p>Repacking requires random access to files in a repository, so that would
require building a fairly complex VFS that works over incremental backup
snapshots.</p>
</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="maybe-we-flush-the-whole-volume">Maybe we flush the whole volume?<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#maybe-we-flush-the-whole-volume" class="hash-link" aria-label="Direct link to Maybe we flush the whole volume?" title="Direct link to Maybe we flush the whole volume?" translate="no">​</a></h3>
<!-- -->
<p>Documentation for <code>FlushFileBuffers</code> says the following:</p>
<blockquote>
<p>To flush all open files on a volume, call FlushFileBuffers with a handle to the volume.
The caller must have administrative privileges.</p>
</blockquote>
<p>While we don’t really want all <strong>open</strong> files, we’re looking for a way
to ensure that the content of all our cached files hits the device. Luckily, the DDK
docs for <code>NtFlushBuffersFileEx</code> say exactly that:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token comment" style="color:rgb(0, 128, 0)">//  If a volume handle is specified:</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token comment" style="color:rgb(0, 128, 0)">//      - Write all modified data for all files on the volume from the</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token comment" style="color:rgb(0, 128, 0)">//        Windows in-memory cache.</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token comment" style="color:rgb(0, 128, 0)">//      - Commit all pending metadata changes for all files on the volume</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token comment" style="color:rgb(0, 128, 0)">//        from the Windows in-memory cache.</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token comment" style="color:rgb(0, 128, 0)">//      - Send a SYNC command to the underlying storage device to commit</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token comment" style="color:rgb(0, 128, 0)">//        all written data in the devices cache to persistent storage.</span><br></div></code></pre></div></div>
<p>Theoretically, if we accompanied every restore with a full volume flush, that would
solve all problems. Flushing the volume doesn’t depend on the number of restored
files. And it only introduces a single flush barrier to the whole operation, allowing
all disk writes to happen asynchronously.</p>
<p>But the requirement for administrative privileges is a deal-breaker. In our case,
the user may not have OS-level administrative privileges but should still be able
to restore a repository from backup. <svg width="24" height="24" viewBox="0 0 16 16" style="vertical-align:middle"><defs><linearGradient id="ic_fluent_dismiss_circle_16_color__a" x1="3.875" y1="2.75" x2="13" y2="16" gradientUnits="userSpaceOnUse"><stop stop-color="#E5484D"></stop><stop offset="1" stop-color="#B54548"></stop></linearGradient><linearGradient id="ic_fluent_dismiss_circle_16_color__b" x1="6.01126" y1="8.19887" x2="8.35442" y2="10.6354" gradientUnits="userSpaceOnUse"><stop stop-color="#FDFDFD"></stop><stop offset="1" stop-color="#FECBE6"></stop></linearGradient></defs><path fill="url(#ic_fluent_dismiss_circle_16_color__a)" d="M8 2C11.3137 2 14 4.68629 14 8C14 11.3137 11.3137 14 8 14C4.68629 14 2 11.3137 2 8C2 4.68629 4.68629 2 8 2Z"></path><path fill="url(#ic_fluent_dismiss_circle_16_color__b)" d="M5.89645 5.89645C6.07001 5.72288 6.33944 5.7036 6.53431 5.83859L6.60355 5.89645L8 7.293L9.39645 5.89645C9.57001 5.72288 9.83944 5.7036 10.0343 5.83859L10.1036 5.89645C10.2771 6.07001 10.2964 6.33944 10.1614 6.53431L10.1036 6.60355L8.707 8L10.1036 9.39645C10.2771 9.57001 10.2964 9.83944 10.1614 10.0343L10.1036 10.1036C9.92999 10.2771 9.66056 10.2964 9.46569 10.1614L9.39645 10.1036L8 8.707L6.60355 10.1036C6.42999 10.2771 6.16056 10.2964 5.96569 10.1614L5.89645 10.1036C5.72288 9.92999 5.7036 9.66056 5.83859 9.46569L5.89645 9.39645L7.293 8L5.89645 6.60355C5.72288 6.42999 5.7036 6.16056 5.83859 5.96569L5.89645 5.89645Z"></path></svg></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="part-4-depression">Part 4: Depression<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#part-4-depression" class="hash-link" aria-label="Direct link to Part 4: Depression" title="Direct link to Part 4: Depression" translate="no">​</a></h2>
<p>Doing the math makes the results look grim.</p>
<p>If you have two million files and each <code>FlushFileBuffers</code> takes just 2 milliseconds,
that’s more than an hour just for the metadata and hardware synchronization.
And that’s before we’ve even accounted for the actual data transfer.</p>
<p>With all known options exhausted, it’s time to accept…</p>
<p>…that we’re ready to start relying on undocumented internals.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="part-5-acceptance">Part 5: Acceptance<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#part-5-acceptance" class="hash-link" aria-label="Direct link to Part 5: Acceptance" title="Direct link to Part 5: Acceptance" translate="no">​</a></h2>
<p>Out of all the proposed solutions, only flushing the volume root seems to address
the root cause of the problem and scale well. We accepted that we’re okay
with undocumented behavior, but what can we really do if flushing the volume
normally requires elevated privileges?</p>
<p>Microsoft has been always known for accurately keeping compatibility and porting
undocumented features, so if there’s a hint, it would be in the code of
the <code>FAT</code> filesystem driver. As it turns, when this driver <a href="https://github.com/microsoft/Windows-driver-samples/blob/5d61a4a79a1e96dc5d9af1e5e712c84507307544/filesys/fastfat/flush.c#L368" target="_blank" rel="noopener noreferrer" class="">handles <code>IRP_MJ_FLUSH_BUFFERS</code></a>,
flushing the volume root directory does exactly the same as flushing the volume.
But that doesn’t require special privileges!</p>
<p>Did this behavior find its way to NTFS and ReFS? Only one way to find out.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="going-practical">Going practical<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#going-practical" class="hash-link" aria-label="Direct link to Going practical" title="Direct link to Going practical" translate="no">​</a></h2>
<p>Below is a quick snippet we can use to open the mount point as a directory and flush it:</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(0, 0, 255)">define</span><span class="token macro property"> </span><span class="token macro property macro-name">WIN32_LEAN_AND_MEAN</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(0, 0, 255)">include</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(163, 21, 21)">&lt;Windows.h&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">WCHAR volumePath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">[</span><span class="token plain">MAX_PATH</span><span class="token punctuation" style="color:rgb(4, 81, 165)">]</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token comment" style="color:rgb(0, 128, 0)">// Resolve the volume mount point.</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token function" style="color:rgb(0, 0, 255)">GetVolumePathName</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">filePath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"> volumePath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"> </span><span class="token function" style="color:rgb(0, 0, 255)">_countof</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">volumePath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token comment" style="color:rgb(0, 128, 0)">// Open the mount point as a directory with FILE_FLAG_BACKUP_SEMANTICS</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token comment" style="color:rgb(0, 128, 0)">// and OPEN_EXISTING flags.</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token comment" style="color:rgb(0, 128, 0)">// NtFlushBuffersFileEx() requires FILE_APPEND_DATA or FILE_WRITE_DATA</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token comment" style="color:rgb(0, 128, 0)">// so we try both of them.</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">HANDLE handle </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(0, 0, 255)">CreateFile</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    volumePath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    FILE_APPEND_DATA</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    FILE_SHARE_READ </span><span class="token operator" style="color:rgb(0, 0, 0)">|</span><span class="token plain"> FILE_SHARE_WRITE </span><span class="token operator" style="color:rgb(0, 0, 0)">|</span><span class="token plain"> FILE_SHARE_DELETE</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token constant" style="color:rgb(129, 31, 63)">NULL</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    OPEN_EXISTING</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    FILE_FLAG_BACKUP_SEMANTICS</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token constant" style="color:rgb(129, 31, 63)">NULL</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token comment" style="color:rgb(0, 128, 0)">// Simplified error checking, better to check for ERROR_ACCESS_DENIED,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token comment" style="color:rgb(0, 128, 0)">// ERROR_NETWORK_ACCESS_DENIED and ERROR_SHARING_VIOLATION.</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:rgb(0, 0, 255)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">handle </span><span class="token operator" style="color:rgb(0, 0, 0)">==</span><span class="token plain"> INVALID_HANDLE_VALUE</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    handle </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(0, 0, 255)">CreateFile</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        volumePath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        FILE_WRITE_DATA</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        FILE_SHARE_READ </span><span class="token operator" style="color:rgb(0, 0, 0)">|</span><span class="token plain"> FILE_SHARE_WRITE </span><span class="token operator" style="color:rgb(0, 0, 0)">|</span><span class="token plain"> FILE_SHARE_DELETE</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        </span><span class="token constant" style="color:rgb(129, 31, 63)">NULL</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        OPEN_EXISTING</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        FILE_FLAG_BACKUP_SEMANTICS</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        </span><span class="token constant" style="color:rgb(129, 31, 63)">NULL</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:rgb(0, 0, 255)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">handle </span><span class="token operator" style="color:rgb(0, 0, 0)">!=</span><span class="token plain"> INVALID_HANDLE_VALUE</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token function" style="color:rgb(0, 0, 255)">FlushFileBuffers</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">handle</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token function" style="color:rgb(0, 0, 255)">CloseHandle</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">handle</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><br></div></code></pre></div></div>
<p>Here is how this program behaves in Process Monitor: <img class="Image_Jtan Border_PJCd" width="654" height="142" src="data:image/webp;base64,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"></p>
<p>So, that <code>FlushFileBuffers</code> call worked, and it took more than a second for the volume.
It’s easy to confirm that the behavior mirrors a volume handle flush, and
experiments also confirm that a physical flush is indeed triggered.</p>
<div class="theme-admonition theme-admonition-tip admonition_Gfwi alert alert--success"><div class="admonitionContent_UjKb"><p>This approach works on FAT, FAT32, NTFS and ReFS.</p></div></div>
<div class="theme-admonition theme-admonition-danger admonition_Gfwi alert alert--danger"><div class="admonitionContent_UjKb"><p>This doesn’t work over the SMB protocol. Fortunately, it’s relatively
straightforward to detect this in advance and select an appropriate fallback.
The same applies if the user doesn’t have any access to the root directory.</p></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-conclusion-undocumented-but-okay-to-use">The conclusion: undocumented, but okay to use<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#the-conclusion-undocumented-but-okay-to-use" class="hash-link" aria-label="Direct link to The conclusion: undocumented, but okay to use" title="Direct link to The conclusion: undocumented, but okay to use" translate="no">​</a></h2>
<p>Sometimes it’s fine to go into a slightly undocumented territory.</p>
<p>Incorporating this trick into our restore implementation allowed us to make the whole
operation durable without sacrificing performance. We replaced per-file flushing with
a single (costly!) flush for the volume root, but got rid of the stacking costs and
allowed our writes to be fully asynchronous.</p>
<p>In this case, examining the FAT driver code indicates that the undocumented behavior
is not accidental. Since it’s shared by FAT, FAT32, NTFS and ReFS, we’d
assume it is there to stay.</p>
<hr>
<!-- -->
<section data-footnotes="true" class="footnotes"><h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI sr-only" id="footnote-label">Footnotes<a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#footnote-label" class="hash-link" aria-label="Direct link to Footnotes" title="Direct link to Footnotes" translate="no">​</a></h2>
<ol>
<li class="anchorTargetHideOnScrollNavbar_vjPI" id="user-content-fn-1-afc97a">
<p>It gets a bit more complex if you also want to guarantee that your half-written
content can’t be seen by others. In that case, you can atomically rename it
into the final destination or use exclusive file sharing bits. <a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#user-content-fnref-1-afc97a" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li class="anchorTargetHideOnScrollNavbar_vjPI" id="user-content-fn-2-afc97a">
<p>Yes, <code>node_modules</code>, I’m looking at you. <a href="https://blog.axiorema.com/engineering/quickly-restoring-1m-files-from-backup/#user-content-fnref-2-afc97a" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
            <category>windows</category>
            <category>performance</category>
            <category>optimization</category>
            <category>backup</category>
            <category>restore</category>
        </item>
        <item>
            <title><![CDATA[Hidden cost of GetFileInformationByHandle]]></title>
            <link>https://blog.axiorema.com/engineering/hidden-cost-getfileinformationbyhandle/</link>
            <guid>https://blog.axiorema.com/engineering/hidden-cost-getfileinformationbyhandle/</guid>
            <pubDate>Tue, 09 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Simplicity often carries an invisible price tag.]]></description>
            <content:encoded><![CDATA[<p>The documentation describes the <a href="https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle" target="_blank" rel="noopener noreferrer" class=""><code>GetFileInformationByHandle</code></a>
Windows API function as a “more basic version” of its advanced variant.
While it offers simplicity and ease of use, that convenience comes at a cost.</p>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-scenario">The scenario<a href="https://blog.axiorema.com/engineering/hidden-cost-getfileinformationbyhandle/#the-scenario" class="hash-link" aria-label="Direct link to The scenario" title="Direct link to The scenario" translate="no">​</a></h2>
<p>It is difficult to find a practical scenario where a single I/O call becomes
the actual bottleneck of an entire operation. But for narrative purposes, it
could be any of the following:</p>
<div class="Container_P0iq"><ol>
<li class="">An application that iterates over thousands of files in various locations, querying
their timestamps</li>
<li class="">A service that frequently reads a small number of “hot” files
and queries their sizes in advance to preallocate buffers</li>
<li class="">A developer so obsessed with the I/O efficiency of a function that
they consciously ignore the fact it only runs once a week<sup><a href="https://blog.axiorema.com/engineering/hidden-cost-getfileinformationbyhandle/#user-content-fn-1-aab473" id="user-content-fnref-1-aab473" data-footnote-ref="true" aria-describedby="footnote-label" class="anchorTargetHideOnScrollNavbar_vjPI">1</a></sup></li>
</ol></div>
<p>Then, at some point you discover that the runtime library you are using is calling
<code>GetFileInformationByHandle</code> to answer those queries.</p>
<p>Maybe the library is relatively old and didn’t know any better at the time,
or maybe it decided to transparently map the result of the API call. Regardless,
this <strong>has doubled</strong> the number of required system calls, and forced them to
retrieve more information than necessary.</p>
<p>How exactly did that happen?</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="legacy-of-getfileinformationbyhandle">Legacy of <code>GetFileInformationByHandle</code><a href="https://blog.axiorema.com/engineering/hidden-cost-getfileinformationbyhandle/#legacy-of-getfileinformationbyhandle" class="hash-link" aria-label="Direct link to legacy-of-getfileinformationbyhandle" title="Direct link to legacy-of-getfileinformationbyhandle" translate="no">​</a></h2>
<p>The <a href="https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle" target="_blank" rel="noopener noreferrer" class=""><code>GetFileInformationByHandle</code></a>
populates a <a href="https://learn.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information" target="_blank" rel="noopener noreferrer" class=""><code>BY_HANDLE_FILE_INFORMATION</code></a>
structure with various information about the file:</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:rgb(0, 0, 255)">struct</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(38, 127, 153)">BY_HANDLE_FILE_INFORMATION</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  DWORD    dwFileAttributes</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  FILETIME ftCreationTime</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  FILETIME ftLastAccessTime</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  FILETIME ftLastWriteTime</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  DWORD    dwVolumeSerialNumber</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  DWORD    nFileSizeHigh</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  DWORD    nFileSizeLow</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  DWORD    nNumberOfLinks</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  DWORD    nFileIndexHigh</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">  DWORD    nFileIndexLow</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><br></div></code></pre></div></div>
<p>However, this structure is just a user-space facade. What we’re actually
interested in is how this maps to the kernel representation of the same information,
i.e., to the NT system calls.</p>
<p>From the structure definition, you might have noticed that the returned information
falls into different categories. And from the standpoint of the NT API, the fields map
to the following information classes:</p>
<table><thead><tr><th>Field</th><th>Information class</th></tr></thead><tbody><tr><td><code>DWORD dwFileAttributes</code></td><td>Basic file information</td></tr><tr><td><code>FILETIME ftCreationTime</code></td><td>Basic file information</td></tr><tr><td><code>FILETIME ftLastAccessTime</code></td><td>Basic file information</td></tr><tr><td><code>FILETIME ftLastWriteTime</code></td><td>Basic file information</td></tr><tr><td><code>DWORD dwVolumeSerialNumber</code></td><td>Volume information</td></tr><tr><td><code>DWORD nFileSizeHigh</code></td><td>Standard file information</td></tr><tr><td><code>DWORD nFileSizeLow</code></td><td>Standard file information</td></tr><tr><td><code>DWORD nNumberOfLinks</code></td><td>Standard file information</td></tr><tr><td><code>DWORD nFileIndexHigh</code></td><td>Internal file information</td></tr><tr><td><code>DWORD nFileIndexLow</code></td><td>Internal file information</td></tr></tbody></table>
<p>Given that there are four different information classes, does filling the
structure require four different syscalls? Let’s find that out.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="going-practical">Going practical<a href="https://blog.axiorema.com/engineering/hidden-cost-getfileinformationbyhandle/#going-practical" class="hash-link" aria-label="Direct link to Going practical" title="Direct link to Going practical" translate="no">​</a></h3>
<p>Below is a quick snippet we can use to compare how those different calls behave,
assuming we’re only interested in basic file information:</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(0, 0, 255)">define</span><span class="token macro property"> </span><span class="token macro property macro-name">WIN32_LEAN_AND_MEAN</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="color:rgb(0, 0, 255)">include</span><span class="token macro property"> </span><span class="token macro property string" style="color:rgb(163, 21, 21)">&lt;Windows.h&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">HANDLE file </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(0, 0, 255)">CreateFile</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    L</span><span class="token string" style="color:rgb(163, 21, 21)">"test"</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    FILE_ALL_ACCESS</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    FILE_SHARE_READ </span><span class="token operator" style="color:rgb(0, 0, 0)">|</span><span class="token plain"> FILE_SHARE_WRITE </span><span class="token operator" style="color:rgb(0, 0, 0)">|</span><span class="token plain"> FILE_SHARE_DELETE</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token constant" style="color:rgb(129, 31, 63)">NULL</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    OPEN_ALWAYS</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token number" style="color:rgb(9, 134, 88)">0</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token constant" style="color:rgb(129, 31, 63)">NULL</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">FILE_BASIC_INFO basicInfo </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token number" style="color:rgb(9, 134, 88)">0</span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token function" style="color:rgb(0, 0, 255)">GetFileInformationByHandleEx</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    file</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    FileBasicInfo</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token operator" style="color:rgb(0, 0, 0)">&amp;</span><span class="token plain">basicInfo</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token keyword" style="color:rgb(0, 0, 255)">sizeof</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">basicInfo</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">BY_HANDLE_FILE_INFORMATION byHandleInfo </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token number" style="color:rgb(9, 134, 88)">0</span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token function" style="color:rgb(0, 0, 255)">GetFileInformationByHandle</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">file</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(0, 0, 0)">&amp;</span><span class="token plain">byHandleInfo</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><br></div></code></pre></div></div>
<p>Here is how this program behaves in Process Monitor: <img class="Image_Jtan Border_PJCd" width="640" height="90" src="data:image/webp;base64,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"></p>
<p>So, while we didn’t get four separate syscalls, <code>GetFileInformationByHandle</code> still
performed two syscalls instead of one:</p>
<ul>
<li class="">
<p>There is a special <code>FileAllInformation</code> class that was used to obtain all three necessary
information categories (basic, standard and internal file information) in a single
call to <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntqueryinformationfile" target="_blank" rel="noopener noreferrer" class=""><code>NtQueryFileInformation</code></a>.</p>
</li>
<li class="">
<p>But volume information is fully separated from file information, so the function
also had to call <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntqueryvolumeinformationfile" target="_blank" rel="noopener noreferrer" class=""><code>NtQueryVolumeInformationFile</code></a>.</p>
</li>
</ul>
<p>Assuming our goal was simply to get the basic file metadata such as its timestamp,
that extra call is just wasted CPU cycles and additional context switch overhead.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="connection-with-posix">Connection with POSIX?<a href="https://blog.axiorema.com/engineering/hidden-cost-getfileinformationbyhandle/#connection-with-posix" class="hash-link" aria-label="Direct link to Connection with POSIX?" title="Direct link to Connection with POSIX?" translate="no">​</a></h3>
<p>While the way this API works can be explained by entirely legacy reasons,
sometimes there are deeper connections to be found.</p>
<p>In this case, the <code>BY_HANDLE_FILE_INFORMATION</code> structure looks remarkably
similar to POSIX <a href="https://pubs.opengroup.org/onlinepubs/007904875/basedefs/sys/stat.h.html" target="_blank" rel="noopener noreferrer" class=""><code>struct stat</code></a>,
both containing the device (volume) ID, number of links, and inode (index)
numbers:</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:rgb(0, 0, 255)">struct</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(38, 127, 153)">stat</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token class-name" style="color:rgb(38, 127, 153)">dev_t</span><span class="token plain">      st_dev</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain">      </span><span class="token comment" style="color:rgb(0, 128, 0)">/* ID of device containing file */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token class-name" style="color:rgb(38, 127, 153)">ino_t</span><span class="token plain">      st_ino</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain">      </span><span class="token comment" style="color:rgb(0, 128, 0)">/* Inode number */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token class-name" style="color:rgb(38, 127, 153)">mode_t</span><span class="token plain">     st_mode</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain">     </span><span class="token comment" style="color:rgb(0, 128, 0)">/* File type and mode */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token class-name" style="color:rgb(38, 127, 153)">nlink_t</span><span class="token plain">    st_nlink</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain">    </span><span class="token comment" style="color:rgb(0, 128, 0)">/* Number of hard links */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token class-name" style="color:rgb(38, 127, 153)">uid_t</span><span class="token plain">      st_uid</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain">      </span><span class="token comment" style="color:rgb(0, 128, 0)">/* User ID of owner */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token class-name" style="color:rgb(38, 127, 153)">gid_t</span><span class="token plain">      st_gid</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain">      </span><span class="token comment" style="color:rgb(0, 128, 0)">/* Group ID of owner */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token class-name" style="color:rgb(38, 127, 153)">dev_t</span><span class="token plain">      st_rdev</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain">     </span><span class="token comment" style="color:rgb(0, 128, 0)">/* Device ID (if special file) */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token class-name" style="color:rgb(38, 127, 153)">off_t</span><span class="token plain">      st_size</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain">     </span><span class="token comment" style="color:rgb(0, 128, 0)">/* Total size, in bytes */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token class-name" style="color:rgb(38, 127, 153)">blksize_t</span><span class="token plain">  st_blksize</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain">  </span><span class="token comment" style="color:rgb(0, 128, 0)">/* Block size for filesystem I/O */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token class-name" style="color:rgb(38, 127, 153)">blkcnt_t</span><span class="token plain">   st_blocks</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain">   </span><span class="token comment" style="color:rgb(0, 128, 0)">/* Number of 512 B blocks allocated */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token keyword" style="color:rgb(0, 0, 255)">struct</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(38, 127, 153)">timespec</span><span class="token plain">  st_atim</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain">  </span><span class="token comment" style="color:rgb(0, 128, 0)">/* Time of last access */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token keyword" style="color:rgb(0, 0, 255)">struct</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(38, 127, 153)">timespec</span><span class="token plain">  st_mtim</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain">  </span><span class="token comment" style="color:rgb(0, 128, 0)">/* Time of last modification */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token keyword" style="color:rgb(0, 0, 255)">struct</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(38, 127, 153)">timespec</span><span class="token plain">  st_ctim</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain">  </span><span class="token comment" style="color:rgb(0, 128, 0)">/* Time of last status change */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-conclusion-be-specific">The conclusion: be specific<a href="https://blog.axiorema.com/engineering/hidden-cost-getfileinformationbyhandle/#the-conclusion-be-specific" class="hash-link" aria-label="Direct link to The conclusion: be specific" title="Direct link to The conclusion: be specific" translate="no">​</a></h2>
<p>This inefficiency can be fixed by using an API that maps with the underlying kernel
primitive, requesting only the data you actually intend to consume:</p>
<ul>
<li class=""><a href="https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex" target="_blank" rel="noopener noreferrer" class=""><code>GetFileInformationByHandleEx</code></a>
with a specific information class, or</li>
<li class=""><a href="https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfilesizeex" target="_blank" rel="noopener noreferrer" class=""><code>GetFileSizeEx</code></a>
which is a convenient wrapper if you only need the file size.</li>
</ul>
<p>By using the more specific APIs, you can cut the syscalls in half and remove
the overhead of querying volume information.</p>
<p>Finally, beware of the odd-looking <code>QueryInformationVolume</code> Process Monitor
entries for files. While they may not contribute to the overall performance
of your application, they can indicate you’re inadvertently using the
more costly version of the API.</p>
<hr>
<!-- -->
<section data-footnotes="true" class="footnotes"><h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI sr-only" id="footnote-label">Footnotes<a href="https://blog.axiorema.com/engineering/hidden-cost-getfileinformationbyhandle/#footnote-label" class="hash-link" aria-label="Direct link to Footnotes" title="Direct link to Footnotes" translate="no">​</a></h2>
<ol>
<li class="anchorTargetHideOnScrollNavbar_vjPI" id="user-content-fn-1-aab473">
<p>This case has happened more times than we care to admit. <a href="https://blog.axiorema.com/engineering/hidden-cost-getfileinformationbyhandle/#user-content-fnref-1-aab473" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
            <category>windows</category>
            <category>performance</category>
            <category>optimization</category>
            <category>syscalls</category>
        </item>
        <item>
            <title><![CDATA[Uncurious case of broken static export and 404’s in Next.js 16]]></title>
            <link>https://blog.axiorema.com/engineering/uncurious-case-broken-static-exports-404s-nextjs-16/</link>
            <guid>https://blog.axiorema.com/engineering/uncurious-case-broken-static-exports-404s-nextjs-16/</guid>
            <pubDate>Wed, 03 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[After an upgrade to Next.js 16, one problem quickly manifested itself with multiple 404 requests in the network inspector.]]></description>
            <content:encoded><![CDATA[<p>Upgrading to a new major version of a framework is rarely too much fun. You may
quickly find yourself wondering if you got lucky and all the problems have already
manifested themselves, or if you’re not hitting the right triggers yet.</p>
<p>We’ve been using Next.js in <code>static export</code> mode for our website. With the
most recent upgrade to Next.js 16, one problem quickly manifested itself with
multiple <strong>404 requests</strong> showing up in the network inspector.</p>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="prefetching-rsc-in-nextjs">Prefetching RSC in Next.js<a href="https://blog.axiorema.com/engineering/uncurious-case-broken-static-exports-404s-nextjs-16/#prefetching-rsc-in-nextjs" class="hash-link" aria-label="Direct link to Prefetching RSC in Next.js" title="Direct link to Prefetching RSC in Next.js" translate="no">​</a></h2>
<p>If you have used Next.js, you may know that the <code>&lt;Link&gt;</code> component used for
intra-site navigation will by default prefetch its target content when it’s
within the viewport. What it fetches is called the React Server Component (RSC)
payload, which contains a <a href="https://nextjs.org/docs/app/getting-started/server-and-client-components#how-do-server-and-client-components-work-in-nextjs" target="_blank" rel="noopener noreferrer" class="">prerendered representation of the server component</a>.</p>
<div class="theme-admonition theme-admonition-info admonition_Gfwi alert alert--info"><div class="admonitionContent_UjKb"><p>RSC payloads are specialized binary data, but they are conventionally
represented as <code>.txt</code> files over the wire.</p></div></div>
<p>Prior to Next.js 16, a typical prefetch would ask for a single file:</p>
<img class="Image_Jtan Border_PJCd" width="536" height="283" src="https://blog.axiorema.com/assets/images/requests-nextjs-15-79b47d399f7d688eef89d06da3c4bc08.webp">
<p>In Next.js 16, the picture changes dramatically:</p>
<img class="Image_Jtan Border_PJCd" width="536" height="283" src="https://blog.axiorema.com/assets/images/requests-nextjs-16-3cb003ecfe97472e454ca861fc49c0e7.webp">
<p>Now, what has really changed, except for the number of requests?</p>
<p>Next.js 16 has a new feature called <a href="https://nextjs.org/docs/app/getting-started/cache-components" target="_blank" rel="noopener noreferrer" class="">Cache Components</a>,
and its implementation has overhauled how RSC is fetched, even if the feature is not used.
In the new fetch structure, different segments are now fetched separately, comprised of
parts like <code>__next._tree.txt</code>, <code>__next._head.txt</code>, and <code>__next._index.txt</code>.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-problem-404-requests-to-rsc">The problem: 404 requests to RSC<a href="https://blog.axiorema.com/engineering/uncurious-case-broken-static-exports-404s-nextjs-16/#the-problem-404-requests-to-rsc" class="hash-link" aria-label="Direct link to The problem: 404 requests to RSC" title="Direct link to The problem: 404 requests to RSC" translate="no">​</a></h2>
<p>As you might have noticed, some of those requests now result in 404 errors. While
those errors don’t crash the application, they effectively disable prefetching
and degrade the user experience.</p>
<p>So what’s causing that? As it turns out, there is a mismatch between the on-disk
generated files and the URL paths requested during the prefetch:</p>
<ul>
<li class="">The on-disk path is: <code>__next/company/__PAGE__.txt</code> (nested directories).</li>
<li class="">The request path is: <code>__next.company.__PAGE__.txt</code> (dot-separated filename).</li>
</ul>
<p>The root cause seems quite unremarkable, and there is <a href="https://github.com/vercel/next.js/issues/85374" target="_blank" rel="noopener noreferrer" class="">an existing bug report</a>
upstream. Apparently, the path construction logic diverged between the client router
and the build output on Windows.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-workaround-a-build-adapter">The workaround: a build adapter<a href="https://blog.axiorema.com/engineering/uncurious-case-broken-static-exports-404s-nextjs-16/#the-workaround-a-build-adapter" class="hash-link" aria-label="Direct link to The workaround: a build adapter" title="Direct link to The workaround: a build adapter" translate="no">​</a></h2>
<p>Until the fix for the core issue arrives, the problem can be worked around.</p>
<p>The new segment cache still feels experimental, so why not tackle it with
another experimental feature? Next.js 16 introduced build adapters, so let’s
use one to rename the files and put them into their expected places.</p>
<p>Add this module somewhere in your source tree (e.g., <code>build/adapter.js</code>):</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:rgb(0, 0, 255)">const</span><span class="token plain"> fs </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(0, 0, 255)">require</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token string" style="color:rgb(163, 21, 21)">"fs"</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:rgb(0, 0, 255)">const</span><span class="token plain"> path </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(0, 0, 255)">require</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token string" style="color:rgb(163, 21, 21)">"path"</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token doc-comment comment" style="color:rgb(0, 128, 0)">/** </span><span class="token doc-comment comment keyword" style="color:rgb(0, 0, 255)">@type</span><span class="token doc-comment comment" style="color:rgb(0, 128, 0)"> </span><span class="token doc-comment comment class-name punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token doc-comment comment class-name keyword" style="color:rgb(0, 0, 255)">import</span><span class="token doc-comment comment class-name punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token doc-comment comment class-name string" style="color:rgb(163, 21, 21)">"next"</span><span class="token doc-comment comment class-name punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token doc-comment comment class-name punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token doc-comment comment class-name" style="color:rgb(38, 127, 153)">NextAdapter</span><span class="token doc-comment comment class-name punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token doc-comment comment" style="color:rgb(0, 128, 0)"> */</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:rgb(0, 0, 255)">const</span><span class="token plain"> adapter </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token comment" style="color:rgb(0, 128, 0)">// https://github.com/vercel/next.js/issues/85374</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token literal-property property">name</span><span class="token operator" style="color:rgb(0, 0, 0)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(163, 21, 21)">"fix-issue-85374"</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token keyword" style="color:rgb(0, 0, 255)">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(0, 0, 255)">onBuildComplete</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token parameter punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token parameter"> outputs </span><span class="token parameter punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        </span><span class="token keyword control-flow" style="color:rgb(0, 0, 255)">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token keyword" style="color:rgb(0, 0, 255)">const</span><span class="token plain"> file </span><span class="token keyword" style="color:rgb(0, 0, 255)">of</span><span class="token plain"> outputs</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token property-access">staticFiles</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">            </span><span class="token keyword" style="color:rgb(0, 0, 255)">const</span><span class="token plain"> sourcePath </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> file</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token property-access">filePath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">            </span><span class="token keyword" style="color:rgb(0, 0, 255)">const</span><span class="token plain"> targetPath </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(0, 0, 255)">fixupPath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">sourcePath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">            </span><span class="token keyword control-flow" style="color:rgb(0, 0, 255)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">targetPath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">                </span><span class="token keyword control-flow" style="color:rgb(0, 0, 255)">await</span><span class="token plain"> fs</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token property-access">promises</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token method function property-access" style="color:rgb(0, 0, 255)">rename</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">sourcePath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"> targetPath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:rgb(0, 0, 255)">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(0, 0, 255)">fixupPath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token parameter">filePath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token keyword" style="color:rgb(0, 0, 255)">const</span><span class="token plain"> components </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> filePath</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token method function property-access" style="color:rgb(0, 0, 255)">split</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">path</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token property-access">sep</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token keyword" style="color:rgb(0, 0, 255)">const</span><span class="token plain"> idx </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> components</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token method function property-access" style="color:rgb(0, 0, 255)">findIndex</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token parameter">x</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(0, 0, 0)">=&gt;</span><span class="token plain"> x</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token method function property-access" style="color:rgb(0, 0, 255)">startsWith</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token string" style="color:rgb(163, 21, 21)">"__next."</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token keyword control-flow" style="color:rgb(0, 0, 255)">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">idx </span><span class="token operator" style="color:rgb(0, 0, 0)">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(9, 134, 88)">0</span><span class="token plain"> </span><span class="token operator" style="color:rgb(0, 0, 0)">&amp;&amp;</span><span class="token plain"> idx </span><span class="token operator" style="color:rgb(0, 0, 0)">&lt;</span><span class="token plain"> components</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token property-access">length</span><span class="token plain"> </span><span class="token operator" style="color:rgb(0, 0, 0)">-</span><span class="token plain"> </span><span class="token number" style="color:rgb(9, 134, 88)">1</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        </span><span class="token comment" style="color:rgb(0, 128, 0)">// Flatten rest of the segments into single dot-separated name.</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        </span><span class="token keyword" style="color:rgb(0, 0, 255)">const</span><span class="token plain"> result </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> components</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token method function property-access" style="color:rgb(0, 0, 255)">slice</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token number" style="color:rgb(9, 134, 88)">0</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"> idx</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        result</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token method function property-access" style="color:rgb(0, 0, 255)">push</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">components</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token method function property-access" style="color:rgb(0, 0, 255)">slice</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">idx</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token method function property-access" style="color:rgb(0, 0, 255)">join</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token string" style="color:rgb(163, 21, 21)">"."</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        </span><span class="token keyword control-flow" style="color:rgb(0, 0, 255)">return</span><span class="token plain"> result</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token method function property-access" style="color:rgb(0, 0, 255)">join</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token plain">path</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token property-access">sep</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token keyword control-flow" style="color:rgb(0, 0, 255)">else</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        </span><span class="token keyword control-flow" style="color:rgb(0, 0, 255)">return</span><span class="token plain"> </span><span class="token keyword null nil" style="color:rgb(0, 0, 255)">null</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">module</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> adapter</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><br></div></code></pre></div></div>
<p>Then, reference it from your <code>next.config.ts</code>:</p>
<div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:rgb(0, 0, 255)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"> NextConfig </span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(0, 0, 255)">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(163, 21, 21)">"next"</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:rgb(0, 0, 255)">const</span><span class="token plain"> config</span><span class="token operator" style="color:rgb(0, 0, 0)">:</span><span class="token plain"> NextConfig </span><span class="token operator" style="color:rgb(0, 0, 0)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    output</span><span class="token operator" style="color:rgb(0, 0, 0)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(163, 21, 21)">"export"</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token comment" style="color:rgb(0, 128, 0)">// … other configuration</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    experimental</span><span class="token operator" style="color:rgb(0, 0, 0)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(4, 81, 165)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">        adapterPath</span><span class="token operator" style="color:rgb(0, 0, 0)">:</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(0, 0, 255)">require</span><span class="token punctuation" style="color:rgb(4, 81, 165)">.</span><span class="token function" style="color:rgb(0, 0, 255)">resolve</span><span class="token punctuation" style="color:rgb(4, 81, 165)">(</span><span class="token string" style="color:rgb(163, 21, 21)">"./build/adapter.js"</span><span class="token punctuation" style="color:rgb(4, 81, 165)">)</span><span class="token punctuation" style="color:rgb(4, 81, 165)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token punctuation" style="color:rgb(4, 81, 165)">}</span><span class="token punctuation" style="color:rgb(4, 81, 165)">;</span><br></div></code></pre></div></div>
<p>This forces the nested file paths to become the flat, dot-separated filenames the client expects.</p>]]></content:encoded>
            <category>web</category>
            <category>nextjs</category>
            <category>regression</category>
            <category>react</category>
        </item>
    </channel>
</rss>