<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://vitordaniel.is-a.dev</id>
    <title>Blog de Vitor Daniel</title>
    <updated>2026-02-05T19:29:39.000Z</updated>
    <generator>SvelteKit</generator>
    <author>
        <name>Vitor Daniel</name>
        <uri>https://vitordaniel.is-a.dev</uri>
    </author>
    <link rel="alternate" href="https://vitordaniel.is-a.dev"/>
    <link rel="self" href="https://vitordaniel.is-a.dev/atom.xml"/>
    <subtitle>Artigos sobre desenvolvimento web e tecnologia</subtitle>
    <rights>© 2026 Vitor Daniel. Todos os direitos reservados.</rights>
    <entry>
        <title type="html"><![CDATA[Hackeei minha universidade e obtive acesso aos dados de todos os alunos]]></title>
        <id>https://vitordaniel.is-a.dev/blog/como-eu-encontrei-uma-vulnerabilidade-no-sistema-da-minha-universidade</id>
        <link href="https://vitordaniel.is-a.dev/blog/como-eu-encontrei-uma-vulnerabilidade-no-sistema-da-minha-universidade"/>
        <link rel="enclosure" href="https://vitordaniel.is-a.dev/_app/immutable/assets/cover.DlstSInX.webp" type="image/webp"/>
        <updated>2026-02-05T19:29:39.000Z</updated>
        <summary type="html"><![CDATA[Um relato pessoal sobre como descobri e reportei uma vulnerabilidade crítica de segurança no sistema da UFRN]]></summary>
        <content type="html"><![CDATA[<h2 id="introdução"><a class="anchor-link" aria-hidden tabindex="-1" href="#introdução">#</a>Introdução</h2>
<p>No momento em que escrevo esta publicação, estou indo para o 3º período do Bacharelado em Tecnologia da Informação na Universidade Federal do Rio Grande do Norte (UFRN). E sim, é isso mesmo que você leu no título. Mas calma, não se preocupe: os dados de todo mundo estão protegidos e nada foi vazado. Deixe-me contar melhor como tudo isso aconteceu.</p>
<p>O sistema de gestão acadêmica utilizado pela UFRN é o <strong>SIGAA</strong> (Sistema Integrado de Gestão de Atividades Acadêmicas), desenvolvido aqui pela Superintendência de Tecnologia da Informação (STI) da universidade. Ele é amplamente utilizado por dezenas de instituições em todo o Brasil, incluindo outras universidades federais (UnB, UFC, UFPB, UFPI), universidades estaduais e institutos federais. Não tenho números exatos, mas o total de usuários, somando todas as instituições, pode ultrapassar 1 milhão.</p>
<p>A STI/UFRN mantém uma API que permite interagir com dados do SIGAA e de outros sistemas. Essa API é de uso restrito e, normalmente, é necessário um processo formal para obter credenciais. Um dos clientes dessa API é o <strong>SIGAA Mobile</strong>, um app nativo com interface simples que permite aos alunos acessarem notas, horários e notícias.</p>
<h2 id="a-curiosidade-matou-o-gato-quase"><a class="anchor-link" aria-hidden tabindex="-1" href="#a-curiosidade-matou-o-gato-quase">#</a>A Curiosidade Matou o Gato? (Quase)</h2>
<p>Como estudante de TI, sou naturalmente curioso sobre o funcionamento das coisas e gosto de criar ferramentas que facilitem a vida. No ensino médio (IFRN), ajudei a criar um aplicativo (<a href="https://www.instagram.com/app.save/" target="_blank">App Save</a>) que resolvia a falta de uma interface mobile decente para o sistema de lá.</p>
<p>Eu tinha planos de fazer algo parecido para a UFRN, talvez um chatbot com IA para consultar notas e outras informações. Como eu não sabia da existência da API naquele momento (e mesmo se soubesse não teria as credenciais), resolvi fazer engenharia reversa para entender como o <strong>SIGAA Mobile</strong> funcionava. Instalei o app no emulador Android <a href="https://www.genymotion.com" target="_blank">Genymotion</a> e utilizei o <a href="https://httptoolkit.com" target="_blank">HTTP Toolkit</a> para inspecionar as requisições (man-in-the-middle) e entender o tráfego de dados. Tudo isso em um ambiente controlado, usando apenas minha própria conta.</p>
<p><img src="./httptoolkit.png" alt="Print do HTTP Toolkit interceptando requisições"></p>
<p>Ao inspecionar o tráfego, descobri os a existência da API, e consegui encontrar a documentação. A partir daí, comecei a estudar como ela se comportava: testei extensivamente vários endpoints para ver quais dados retornavam e quais eram os limites de validação (também testei inputs como <code>9999999999</code>, <code>0</code> e <code>-1</code> só para ver se o que acontecia 🙃).</p>
<p>A API é complexa — possui centenas de endpoints. O fluxo de dados é fragmentado: para começar, eu precisava primeiro pegar meu <code>id_usuario</code>, depois listar meus <code>vinculos</code> (graduação, mestrado, etc.), selecionar o vínculo ativo e só então chamar os enpoints que eu queria (notas, turmas, etc).</p>
<p>Muitos endpoints retornavam acesso negado, outros traziam apenas dados públicos. Mas eu continuei "cutucando".</p>
<h2 id="o-momento-eita"><a class="anchor-link" aria-hidden tabindex="-1" href="#o-momento-eita">#</a>O Momento "Eita..."</h2>
<p>Em certo momento, me deparei com um endpoint relacionado a busca de "usuários". Resolvi testar, esperando receber um erro de permissão.</p>
<p>Quando executei a requisição, veio a surpresa: a API retornou o objeto JSON completo contendo <strong>nome, CPF e e-mail pessoal</strong> de usuários cadastrados no sistema. Isso incluía não apenas alunos, mas provavelmente professores e servidores.</p>
<p>Fiquei em choque. Cheguei a cogitar se aqueles dados seriam públicos por alguma lei de transparência, mas pesquisei e vi que, à luz da <strong>LGPD</strong>, aquilo era uma exposição crítica. Essa falha figura no topo da lista de problemas de segurança mais comuns da <a href="https://owasp.org/Top10/2021/A01_2021-Broken_Access_Control/" target="_blank">OWASP Top 10 de 2025</a>.</p>
<p>Não explorei a fundo para não coletar dados indevidos, mas o potencial de extração era massivo, abrangendo registros de décadas.</p>
<p>Naquele momento, o medo bateu. "Será que serei processado?", "Será se foi errado eu ter explorado o sistema dessa maneira?". Mas a ética falou mais alto: eu precisava reportar aquilo antes que alguém mal-intencionado descobrisse.</p>
<h2 id="responsible-disclosure-divulgação-responsável"><a class="anchor-link" aria-hidden tabindex="-1" href="#responsible-disclosure-divulgação-responsável">#</a>Responsible Disclosure (Divulgação Responsável)</h2>
<p>Imediatamente interrompi os testes e redigi um relatório técnico. Enviei um e-mail para a STI detalhando a vulnerabilidade, o passo a passo para reprodução e o impacto (exposição de CPF/E-mails), deixando claro que <strong>não realizei extração de dados de terceiros</strong>, apenas a validação da falha.</p>
<p>A resposta foi exemplar.</p>
<p>A equipe da STI entrou em contato comigo no mesmo dia. Tive uma reunião com a diretoria, onde expliquei o ocorrido. Recebi agradecimentos pela postura ética e profissional. Fui convidado a participar de processos seletivos para bolsas para me juntar à equipe e mantivemos o acordo de que eu só falaria publicamente sobre isso após a correção.</p>
<p>O <em>patch</em> de segurança foi aplicado poucos dias depois, corrigindo as permissões de acesso nos endpoints afetados.</p>
<h2 id="conclusão"><a class="anchor-link" aria-hidden tabindex="-1" href="#conclusão">#</a>Conclusão</h2>
<p>Fiquei muito feliz com o desfecho. A STI demonstrou ser uma equipe madura e profissional, e fico honrado em ter contribuído — mesmo que acidentalmente — para a segurança dos dados de toda a comunidade acadêmica da UFRN.</p>
<p>Essa experiência reforçou para mim que, agir com ética e responsabilidade, mesmo em situações delicadas, é sempre o melhor caminho.</p>
<!--
Além disso, tive uma conversa com o criador do HTTP Toolkit. É uma ferramenta open source incrível, que me permitiu fazer o que fiz. Ela possui uma versão PRO com alguns recursos extras. Resolvi mandar um e-mail para o criador, explicando que eu sou estudante e como usei a ferramenta, e perguntei se seria possível obter uma licença da versão PRO gratuitamente; ele, de muito bom grado, aceitou.

![](./tim_email.png)

Ele também me convidou para escrever uma postagem para o blog do HTTP Toolkit falando sobre isso. Esse post deve sair nos próximos dias.
-->]]></content>
        <author>
            <name>Vitor Daniel</name>
            <email>vitor@vitordaniel.is-a.dev</email>
            <uri>https://vitordaniel.is-a.dev</uri>
        </author>
        <published>2026-02-05T19:29:39.000Z</published>
        <rights>© 2026 Vitor Daniel</rights>
    </entry>
    <entry>
        <title type="html"><![CDATA[Como baixar uma única pasta de um repositório no GitHub]]></title>
        <id>https://vitordaniel.is-a.dev/blog/como-baixar-uma-pasta-de-um-repositorio-github</id>
        <link href="https://vitordaniel.is-a.dev/blog/como-baixar-uma-pasta-de-um-repositorio-github"/>
        <link rel="enclosure" href="https://vitordaniel.is-a.dev/_app/immutable/assets/cover.CgGLY0vZ.webp" type="image/webp"/>
        <updated>2026-01-11T02:38:21.000Z</updated>
        <summary type="html"><![CDATA[Aprenda a baixar apenas uma pasta específica de um repositório no GitHub, sem precisar clonar todo o repositório.]]></summary>
        <content type="html"><![CDATA[<h2 id="introdução"><a class="anchor-link" aria-hidden tabindex="-1" href="#introdução">#</a>Introdução</h2>
<p>Às vezes precisamos baixar uma pasta de um repositório no GitHub sem clonar tudo. Por exemplo, quando você quer acessar apenas a pasta "exemplos" de um projeto. Claro você pode simplesmente clonar o repositório inteiro, mas você pode querer algo mais simples, ou o reposítório é muito grande,o que demora para baixar e consome muito espaço. Vou mostrar três formas práticas de fazer isso.</p>
<h2 id="1-usando-o-downgit-ferramenta-online"><a class="anchor-link" aria-hidden tabindex="-1" href="#1-usando-o-downgit-ferramenta-online">#</a>1. Usando o DownGit (ferramenta online)</h2>
<p>Uma das maneiras mais fáceis é utilizando a ferramenta online <a href="https://downgit.github.io/" target="_blank">DownGit</a>, ele cria um arquivo ZIP contendo apenas o conteúdo da pasta desejada. Siga os passos abaixo:</p>
<ol>
<li>Acesse o <a href="https://downgit.github.io/" target="_blank">DownGit</a>.</li>
<li>Cole a URL da pasta do GitHub (ex: <code>https://github.com/usuario/repo/tree/main/pasta</code>).</li>
<li>Clique em <strong>Download</strong>.</li>
</ol>
<p><strong>Dica:</strong> Você pode criar links para download diretos prefixando a URL da pasta com <code>https://downgit.github.io/#/home?url=</code>.</p>
<h2 id="2-usando-o-degit-nodejs"><a class="anchor-link" aria-hidden tabindex="-1" href="#2-usando-o-degit-nodejs">#</a>2. Usando o Degit (Node.js)</h2>
<p>Outra opção é utilizar a ferramenta de linha de comando <a href="https://github.com/Rich-Harris/degit" target="_blank">Degit</a>. Ela vai fazer o download de todos os arquivos do repositório, sem o histórico do Git (sem a pasta <code>.git</code>, o que o torna mais leve que o <code>git clone</code>), mas permite que você extraia apenas a pasta desejada. Basta executar o comando abaixo:</p>
<div class="expressive-code"><style>.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre > code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:'gutter code';grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter > *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, ' ');padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:'';position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:'\a0'}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:'';position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:'';position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:'';position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:'';position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:'';position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:'';position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:'';position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root .main-pane{z-index:1}.expressive-code:hover .twoslash-hover:not(.twoslash-hover:hover){border-color:rgba(from var(--ec-twoSlash-hoverUnderlineCol) r g b / 0.4)}@media (min-width: 500px){.expressive-code .twoslash-popup-container:before{content:"";position:absolute;top:-5px;left:3px;border-top:1px solid var(--ec-twoSlash-brdCol);border-right:1px solid var(--ec-twoSlash-brdCol);background:var(--ec-twoSlash-bg);transform:rotate(-45deg);width:8px;height:8px;pointer-events:none;display:inline-block}}.expressive-code .twoslash-popup-container{position:absolute;z-index:999 !important;background:var(--ec-twoSlash-bg);border:1px solid var(--ec-twoSlash-brdCol);border-radius:4px;font-size:90%;white-space:nowrap !important;word-break:normal !important;overflow-wrap:normal !important;width:max-content !important;margin-top:0.5rem;color:var(--ec-twoSlash-textCol)}.expressive-code .twoslash-popup-container a:link{color:var(--ec-twoSlash-linkCol)}.expressive-code .twoslash-popup-container a:hover{color:var(--ec-twoSlash-linkColHover)}.expressive-code .twoslash-popup-container a:visited{color:var(--ec-twoSlash-linkColVisited)}.expressive-code .twoslash-popup-container a:active{color:var(--ec-twoSlash-linkColAct)}.expressive-code .twoslash-static-container{display:block;z-index:10;background:var(--ec-twoSlash-bg);border:1px solid var(--ec-twoSlash-brdCol);border-radius:4px;font-size:90%;white-space:nowrap !important;word-break:normal !important;overflow-wrap:normal !important;width:max-content !important}.expressive-code .twoslash-static-container a:link{color:var(--ec-twoSlash-linkCol)}.expressive-code .twoslash-static-container a:hover{color:var(--ec-twoSlash-linkColHover)}.expressive-code .twoslash-static-container a:visited{color:var(--ec-twoSlash-linkColVisited)}.expressive-code .twoslash-static-container a:active{color:var(--ec-twoSlash-linkColAct)}.expressive-code .twoslash-static-container:before{content:"";position:absolute;top:-4px;left:2px;border-top:1px solid var(--ec-twoSlash-brdCol);border-right:1px solid var(--ec-twoSlash-brdCol);background:var(--ec-twoSlash-bg);transform:rotate(-45deg);width:10px;height:10px;pointer-events:none;display:inline-block}.expressive-code .twoslash-static-container *{white-space:wrap !important;word-break:normal !important;overflow-wrap:normal !important}.expressive-code .twoslash,.expressive-code .twoslash-noline{position:relative}@media (prefers-reduced-motion: reduce){.expressive-code .twoslash *,.expressive-code .twoslash-noline *{transition:none !important}}.expressive-code .twoslash .twoslash-hover{position:relative;border-bottom:1px dashed transparent;transition-timing-function:ease;transition:border-color 0.3s}.expressive-code .twoslash:hover .twoslash-hover{border-color:var(--ec-twoSlash-hoverUnderlineCol)}.expressive-code .twoslash-popup-code{display:block;width:100%;max-width:600px;padding:6px 12px;font-size:var(--ec-codeFontSize);font-weight:400;line-height:var(--ec-codeLineHt);white-space:pre-wrap}.expressive-code .twoslash-popup-code,.expressive-code .twoslash-popup-code span{white-space:preserve !important}.expressive-code .twoslash-popup-code-type{font-family:var(--ec-codeFontFml);font-weight:600}.expressive-code .twoslash-popup-code-type .frame pre{display:contents !important}.expressive-code .twoslash-popup-code-type .frame .ec-line{display:unset !important}.expressive-code .twoslash-popup-code-type .frame .ec-line .code{padding-inline-start:0 !important;border-inline-start:none !important}.expressive-code .twoslash-popup-code-type .frame pre > code{padding:0 !important}.expressive-code .twoslash-popup-code-type .frame{box-shadow:none !important}.expressive-code .twoslash-popup-docs .frame{box-shadow:none !important}.expressive-code .twoslash-popup-code-type .frame .header::before{border:none !important}.expressive-code .twoslash-popup-code::-webkit-scrollbar,.expressive-code .twoslash-popup-code::-webkit-scrollbar-track,.expressive-code .twoslash-popup-docs::-webkit-scrollbar,.expressive-code .twoslash-popup-docs::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code .twoslash-popup-code::-webkit-scrollbar-thumb,.expressive-code .twoslash-popup-docs::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code .twoslash-popup-code::-webkit-scrollbar-thumb:hover,.expressive-code .twoslash-popup-docs::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code .twoslash-popup-code::-webkit-scrollbar-corner,.expressive-code .twoslash-popup-docs::-webkit-scrollbar-corner{background:transparent;width:0;height:0}.expressive-code .twoslash-popup-code,.expressive-code .twoslash-popup-docs{max-height:var(--ec-twoSlash-popupDocsMaxHt) !important;overflow:auto !important}.expressive-code .twoslash-popup-docs{max-width:600px;padding-left:12px;padding-right:12px;padding-top:6px;padding-bottom:6px;border-top:1px solid var(--ec-twoSlash-brdCol);font-size:var(--ec-codeFontSize);font-weight:400;line-height:var(--ec-codeLineHt);text-wrap:balance}.expressive-code .twoslash-popup-docs code{font-family:var(--ec-codeFontFml);font-weight:var(--ec-codeFontWg)}.expressive-code .twoslash-popup-docs-tagline{display:flex;text-wrap-style:stable}.expressive-code .twoslash-popup-docs-tag-name{color:var(--ec-twoSlash-tagCol);font-style:italic;--shiki-dark-font-style:italic;font-weight:500;margin-right:0.25rem}.expressive-code .twoslash-popup-docs-tag-value{margin-left:0.25rem}.expressive-code .twoslash-popup-docs pre{width:100%;background-color:var(--ec-frm-edBg) !important;padding:.15rem;border-radius:4px !important;position:relative !important;font-family:var(--ec-codeFontFml);display:inline-block !important;line-height:var(--ec-codeLineHt);border:var(--ec-brdWd) solid var(--ec-twoSlash-brdCol) !important}.expressive-code .twoslash-popup-docs.twoslash-popup-docs-tags{font-size:14px !important;margin:0 !important;padding-top:0 !important;padding-bottom:0 !important;padding-left:12px !important;padding-right:12px !important}.expressive-code .twoslash-popup-docs > pre > code{border:none !important;outline:none !important;width:100% !important;padding:0.15rem !important}.expressive-code .twoslash-popup-docs code{background-color:var(--ec-frm-edBg) !important;padding:.125rem !important;border-radius:4px !important;position:relative !important;display:inline-block !important;line-height:var(--ec-codeLineHt)}.expressive-code .twoslash-popup-docs-tag-value code,.expressive-code .twoslash-popup-docs > p > code,.expressive-code .twoslash-popup-docs > p > a > code,.expressive-code .twoslash-popup-docs > ul > li > code{border:1px solid var(--ec-twoSlash-brdCol);border-radius:4px}.expressive-code .twoslash-popup-docs code span::after{content:none !important}.expressive-code .twoslash .twoslash-completion{position:relative;margin-top:0.1rem}.expressive-code .twoslash-completion-container{display:flex;flex-direction:column;z-index:10;background:var(--ec-twoSlash-completionBoxBg);border:1px solid var(--ec-twoSlash-completionBoxBrd);border-radius:4px;font-size:90%;white-space:nowrap !important;word-break:normal !important;overflow-wrap:normal !important;width:max-content !important;padding:0.15rem;padding-left:0.25rem;padding-right:0.25rem}.expressive-code .twoslash-cursor{content:" ";width:3px;height:18px;background-color:var(--ec-twoSlash-cursorCol);display:inline-block;margin-left:1px;animation:cursor-blink 1.5s steps(2) infinite;align-self:center}@keyframes cursor-blink{0%{opacity:0}}.expressive-code .twoslash-completion-container *{white-space:wrap !important;word-break:normal !important;overflow-wrap:normal !important}.expressive-code .twoslash-completion-item{overflow:hidden;display:flex;align-items:center;gap:0.25em}.expressive-code .twoslash-completion-item:hover{background:var(--ec-twoSlash-completionBoxHoverBg)}.expressive-code .twoslash-completion-item-separator{border-top:1px solid var(--ec-twoSlash-completionBoxBrd)}.expressive-code .twoslash-completion-item-deprecated{text-decoration:line-through;opacity:0.5}.expressive-code .twoslash-completion-name{font-weight:400}.expressive-code .twoslash-completion-name-unmatched{color:var(--ec-twoSlash-completionBoxCol)}.expressive-code .twoslash-completion-name-matched{color:var(--ec-twoSlash-completionBoxMatchedCol);font-weight:600}.expressive-code .twoslash-completion-icon{color:var(--ec-twoSlash-completionBoxCol);margin-right:0.2rem;width:1em;flex:none}.expressive-code .twoslash-completion-icon.class{color:var(--ec-twoSlash-completionIconClass)}.expressive-code .twoslash-completion-icon.constructor{color:var(--ec-twoSlash-completionIconConstructor)}.expressive-code .twoslash-completion-icon.function{color:var(--ec-twoSlash-completionIconFunction)}.expressive-code .twoslash-completion-icon.interface{color:var(--ec-twoSlash-completionIconInterface)}.expressive-code .twoslash-completion-icon.module{color:var(--ec-twoSlash-completionIconModule)}.expressive-code .twoslash-completion-icon.method{color:var(--ec-twoSlash-completionIconMethod)}.expressive-code .twoslash-completion-icon.property{color:var(--ec-twoSlash-completionIconProperty)}.expressive-code .twoslash-completion-icon.string{color:var(--ec-twoSlash-completionIconString)}.expressive-code .twoslash-noline .twoslash-static{position:relative}.expressive-code .twoslash.twoerror{display:flex}.expressive-code .twoslash-error-underline{text-decoration-line:spelling-error;position:relative}.expressive-code .twoslash-error-box{display:flex;z-index:10;padding:0.1rem 0.3rem;border-radius:0.2rem;font-style:italic;border:1px solid var(--ec-twoSlash-brdCol);border-radius:4px;font-size:90%;white-space:nowrap !important;word-break:normal !important;overflow-wrap:normal !important;flex:0 1 100%}.expressive-code .twoslash-error-box .twoslash-error-box-icon,.expressive-code .twoslash-error-box .twoslash-error-box-content{display:inline-block;vertical-align:middle}.expressive-code .twoslash-error-box-content{flex:0 1 100%}.expressive-code .twoslash-error-box-content-message{white-space:normal}.expressive-code .twoslash-error-level-error{color:var(--ec-twoSlash-errorCol) !important;border-color:rgba(from var(--ec-twoSlash-errorCol) r g b / 0.25) !important;background:rgba(from var(--ec-twoSlash-errorCol) r g b / 0.1) !important}.expressive-code .twoslash-error-level-warning{color:var(--ec-twoSlash-warnCol) !important;border-color:rgba(from var(--ec-twoSlash-warnCol) r g b / 0.25) !important;background:rgba(from var(--ec-twoSlash-warnCol) r g b / 0.1) !important}.expressive-code .twoslash-error-level-suggestion{color:var(--ec-twoSlash-suggestionCol) !important;border-color:rgba(from var(--ec-twoSlash-suggestionCol) r g b / 0.25) !important;background:rgba(from var(--ec-twoSlash-suggestionCol) r g b / 0.1) !important}.expressive-code .twoslash-error-level-message{color:var(--ec-twoSlash-messageCol) !important;border-color:rgba(from var(--ec-twoSlash-messageCol) r g b / 0.25) !important;background:rgba(from var(--ec-twoSlash-messageCol) r g b / 0.1) !important}.expressive-code .twoslash-highlighted{background-color:var(--ec-twoSlash-hlBg);border:1px solid var(--ec-twoSlash-hlBrdCol);padding:1px 2px;margin:-1px -3px;border-radius:4px}.expressive-code .twoslash-custom-box{margin-left:0rem;margin-right:0rem;padding-left:0.5rem;padding-right:0.5rem;display:block;z-index:10;padding:0.1rem 0.3rem;border-radius:0.2rem;font-style:italic;border:1px solid var(--ec-twoSlash-brdCol);border-radius:4px;font-size:90%;white-space:nowrap !important;word-break:normal !important;overflow-wrap:normal !important;width:100% !important}.expressive-code .twoslash-custom-box .twoslash-custom-box-icon,.expressive-code .twoslash-custom-box .twoslash-custom-box-content{display:inline-block;vertical-align:middle}.expressive-code .twoslash-custom-box .twoslash-custom-box-icon{margin-right:0.5rem;height:1rem;width:1rem}.expressive-code .twoslash-custom-level-error{color:var(--ec-twoSlash-errorCol) !important;border-color:rgba(from var(--ec-twoSlash-errorCol) r g b / 0.25) !important;background:rgba(from var(--ec-twoSlash-errorCol) r g b / 0.1) !important}.expressive-code .twoslash-custom-level-warning{color:var(--ec-twoSlash-warnCol) !important;border-color:rgba(from var(--ec-twoSlash-warnCol) r g b / 0.25) !important;background:rgba(from var(--ec-twoSlash-warnCol) r g b / 0.1) !important}.expressive-code .twoslash-custom-level-suggestion{color:var(--ec-twoSlash-suggestionCol) !important;border-color:rgba(from var(--ec-twoSlash-suggestionCol) r g b / 0.25) !important;background:rgba(from var(--ec-twoSlash-suggestionCol) r g b / 0.1) !important}.expressive-code .twoslash-custom-level-message{color:var(--ec-twoSlash-messageCol) !important;border-color:rgba(from var(--ec-twoSlash-messageCol) r g b / 0.25) !important;background:rgba(from var(--ec-twoSlash-messageCol) r g b / 0.1) !important}.expressive-code .gutter .ln{display:inline-flex;justify-content:flex-end;align-items:flex-start;box-sizing:content-box;min-width:var(--lnWidth, 2ch);padding-inline:2ch;color:var(--ec-lineNumbers-fg)}.highlight .expressive-code .gutter .ln{color:var(--ec-lineNumbers-hlFg)}.expressive-code .ec-section{position:relative}.expressive-code .ec-section summary{position:relative;font-family:var(--ec-cs-closedFontFml);font-size:var(--ec-cs-closedFontSize);line-height:var(--ec-cs-closedLineHt);user-select:none;-webkit-user-select:none;cursor:pointer;color:var(--ec-cs-closedTextCol);background-color:var(--ec-cs-closedBgCol);--border-color:var(--ec-cs-closedBrdCol);--border-width:var(--ec-cs-closedBrdWd);box-shadow:inset 0 calc(-1 * var(--border-width)) var(--border-color), inset 0 var(--border-width) var(--border-color);margin:var(--ec-cs-closedMarg);padding:0}.expressive-code .ec-section summary::marker{display:inline-block;content:"";width:16px;height:16px}.expressive-code .ec-section summary::-webkit-details-marker{display:none}.expressive-code .ec-section summary :is(.expand, .collapse){position:relative;display:inline-block;width:16px;height:16px;vertical-align:text-bottom;opacity:0.75}.expressive-code .ec-section summary :is(.expand, .collapse)::after{content:'';position:absolute;pointer-events:none;inset:0;background-color:var(--ec-cs-closedTextCol);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;line-height:0}.expressive-code .ec-section summary .expand::after{-webkit-mask-image:var(--ec-cs-expandIcon);mask-image:var(--ec-cs-expandIcon);-webkit-print-color-adjust:exact;print-color-adjust:exact}.expressive-code .ec-section summary .collapse{display:none}.expressive-code .ec-section summary .collapse::after{-webkit-mask-image:var(--ec-cs-collapseIcon);mask-image:var(--ec-cs-collapseIcon)}.expressive-code .ec-section summary .text{margin-left:1em}.expressive-code .ec-section summary .ec-line .code{padding-block:var(--ec-cs-closedPadBlk);text-indent:0}.expressive-code .ec-section[open],.expressive-code .ec-section details[open] + .content-lines{--border-color:var(--ec-cs-openBrdCol);--border-width:var(--ec-cs-openBrdWd);box-shadow:inset 0 calc(-1 * var(--border-width)) var(--border-color), inset 0 var(--border-width) var(--border-color);padding-inline:var(--ec-cs-openPad);margin-inline:var(--ec-cs-openMarg)}.expressive-code .ec-section.github[open] summary{display:none}.expressive-code .ec-section.github[open]{background-color:var(--ec-cs-openBgCol)}.expressive-code .ec-section:is(.collapsible-start, .collapsible-end){display:flex;flex-direction:column}.expressive-code .ec-section:is(.collapsible-start, .collapsible-end) .content-lines{display:none}.expressive-code .ec-section:is(.collapsible-start, .collapsible-end) details[open] .collapse{display:inline-block}.expressive-code .ec-section:is(.collapsible-start, .collapsible-end) details[open] :is(.expand, .text){display:none}.expressive-code .ec-section:is(.collapsible-start, .collapsible-end) details[open] + .content-lines{display:block;background-color:var(--ec-cs-openBgColCollapsible)}@media print{.expressive-code .ec-section:is(.collapsible-start, .collapsible-end) details[open]{display:none}}.expressive-code .ec-section.collapsible-end{flex-direction:column-reverse}:root,:root:not([data-theme='catppuccin-macchiato']) .expressive-code[data-theme='catppuccin-macchiato']{--ec-brdRad:0.3rem;--ec-brdWd:1.5px;--ec-brdCol:#00000000;--ec-codeFontFml:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono','Courier New',monospace;--ec-codeFontSize:0.85rem;--ec-codeFontWg:400;--ec-codeLineHt:1.65;--ec-codePadBlk:1rem;--ec-codePadInl:1.35rem;--ec-codeBg:#24273a;--ec-codeFg:#cad3f5;--ec-codeSelBg:#939ab740;--ec-gtrFg:#8087a2e3;--ec-gtrBrdCol:#8087a233;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#c6a0f6cd;--ec-uiFontFml:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol','Noto Color Emoji';--ec-uiFontSize:0.9rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#5b6078;--ec-uiSelFg:#cad3f5;--ec-focusBrd:#c6a0f6;--ec-sbThumbCol:#5b607880;--ec-sbThumbHoverCol:#6e738d;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:'+';--ec-tm-delDiffIndContent:'-';--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#1e203080;--ec-frm-frameBoxShdCssVal:0.1rem 0.1rem 0.2rem #1e203080;--ec-frm-edActTabBg:#24273a;--ec-frm-edActTabFg:#c6a0f6;--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:#c6a0f6;--ec-frm-edActTabIndBtmCol:#00000000;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.3rem;--ec-frm-edTabBarBg:#181926;--ec-frm-edTabBarBrdCol:#00000000;--ec-frm-edTabBarBrdBtmCol:transparent;--ec-frm-edBg:#24273a;--ec-frm-trmTtbFg:#cad3f5;--ec-frm-trmTtbDotsFg:#cad3f5;--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:#181926;--ec-frm-trmTtbBrdBtmCol:#00000000;--ec-frm-trmBg:#24273a;--ec-frm-inlBtnFg:#cad3f5;--ec-frm-inlBtnBg:#cad3f5;--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnBrd:#cad3f5;--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:#5f7d56;--ec-frm-tooltipSuccessFg:white;--ec-frm-copyIcon:url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2024%2024'%20fill%3D'none'%20stroke%3D'black'%20stroke-width%3D'1.75'%3E%3Cpath%20d%3D'M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201'%2F%3E%3Crect%20x%3D'6'%20y%3D'5'%20width%3D'16'%20height%3D'18'%20rx%3D'1.5'%20ry%3D'1.5'%2F%3E%3C%2Fsvg%3E");--ec-frm-trmIcon:url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2060%2016'%20preserveAspectRatio%3D'xMidYMid%20meet'%3E%3Ccircle%20cx%3D'8'%20cy%3D'8'%20r%3D'8'%2F%3E%3Ccircle%20cx%3D'30'%20cy%3D'8'%20r%3D'8'%2F%3E%3Ccircle%20cx%3D'52'%20cy%3D'8'%20r%3D'8'%2F%3E%3C%2Fsvg%3E");--ec-twoSlash-brdCol:#00000000;--ec-twoSlash-bg:#24273a;--ec-twoSlash-hoverUnderlineCol:#cad3f5;--ec-twoSlash-textCol:#cad3f5;--ec-twoSlash-popupDocsMaxHt:200px;--ec-twoSlash-tagCol:#78a1f6;--ec-twoSlash-linkCol:#78a1f6;--ec-twoSlash-linkColVisited:#f2a9dd;--ec-twoSlash-linkColHover:#63cbc0;--ec-twoSlash-linkColAct:#8ccf7f;--ec-twoSlash-hlBg:#264a8980;--ec-twoSlash-hlBrdCol:#5570b3d0;--ec-twoSlash-errorCol:#ed8796;--ec-twoSlash-warnCol:#eed49f;--ec-twoSlash-suggestionCol:#a6da95;--ec-twoSlash-messageCol:#8aadf4;--ec-twoSlash-cursorCol:#f4dbd6;--ec-twoSlash-completionBoxBg:#1e2030;--ec-twoSlash-completionBoxBrd:#5b6078;--ec-twoSlash-completionBoxCol:#cad3f5;--ec-twoSlash-completionBoxMatchedCol:#c6a0f6;--ec-twoSlash-completionBoxHoverBg:#363a4f;--ec-twoSlash-completionIconClass:#EE9D28;--ec-twoSlash-completionIconConstructor:#b180d7;--ec-twoSlash-completionIconFunction:#b180d7;--ec-twoSlash-completionIconInterface:#75beff;--ec-twoSlash-completionIconModule:#cccccc;--ec-twoSlash-completionIconMethod:#b180d7;--ec-twoSlash-completionIconProperty:#cccccc;--ec-twoSlash-completionIconString:#cccccc;--ec-lineNumbers-fg:inherit;--ec-lineNumbers-hlFg:inherit;--ec-cs-closedBrdWd:0px;--ec-cs-closedPadBlk:4px;--ec-cs-closedMarg:0;--ec-cs-closedFontFml:inherit;--ec-cs-closedFontSize:inherit;--ec-cs-closedLineHt:inherit;--ec-cs-closedTextCol:#cad3f5;--ec-cs-closedBgCol:#91d7e333;--ec-cs-closedBrdCol:#91d7e380;--ec-cs-openBrdWd:1px;--ec-cs-openPad:0;--ec-cs-openMarg:0;--ec-cs-openBgCol:transparent;--ec-cs-openBgColCollapsible:#91d7e31a;--ec-cs-openBrdCol:transparent;--ec-cs-expandIcon:url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2016%2016'%3E%3Cpath%20d%3D'm8.177.677%202.896%202.896a.25.25%200%200%201-.177.427H8.75v1.25a.75.75%200%200%201-1.5%200V4H5.104a.25.25%200%200%201-.177-.427L7.823.677a.25.25%200%200%201%20.354%200ZM7.25%2010.75a.75.75%200%200%201%201.5%200V12h2.146a.25.25%200%200%201%20.177.427l-2.896%202.896a.25.25%200%200%201-.354%200l-2.896-2.896A.25.25%200%200%201%205.104%2012H7.25v-1.25Zm-5-2a.75.75%200%200%200%200-1.5h-.5a.75.75%200%200%200%200%201.5h.5ZM6%208a.75.75%200%200%201-.75.75h-.5a.75.75%200%200%201%200-1.5h.5A.75.75%200%200%201%206%208Zm2.25.75a.75.75%200%200%200%200-1.5h-.5a.75.75%200%200%200%200%201.5h.5ZM12%208a.75.75%200%200%201-.75.75h-.5a.75.75%200%200%201%200-1.5h.5A.75.75%200%200%201%2012%208Zm2.25.75a.75.75%200%200%200%200-1.5h-.5a.75.75%200%200%200%200%201.5h.5Z'%2F%3E%3C%2Fsvg%3E");--ec-cs-collapseIcon:url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2016%2016'%3E%3Cpath%20d%3D'M10.896%202H8.75V.75a.75.75%200%200%200-1.5%200V2H5.104a.25.25%200%200%200-.177.427l2.896%202.896a.25.25%200%200%200%20.354%200l2.896-2.896A.25.25%200%200%200%2010.896%202ZM8.75%2015.25a.75.75%200%200%201-1.5%200V14H5.104a.25.25%200%200%201-.177-.427l2.896-2.896a.25.25%200%200%201%20.354%200l2.896%202.896a.25.25%200%200%201-.177.427H8.75v1.25Zm-6.5-6.5a.75.75%200%200%200%200-1.5h-.5a.75.75%200%200%200%200%201.5h.5ZM6%208a.75.75%200%200%201-.75.75h-.5a.75.75%200%200%201%200-1.5h.5A.75.75%200%200%201%206%208Zm2.25.75a.75.75%200%200%200%200-1.5h-.5a.75.75%200%200%200%200%201.5h.5ZM12%208a.75.75%200%200%201-.75.75h-.5a.75.75%200%200%201%200-1.5h.5A.75.75%200%200%201%2012%208Zm2.25.75a.75.75%200%200%200%200-1.5h-.5a.75.75%200%200%200%200%201.5h.5Z'%2F%3E%3C%2Fsvg%3E")}.expressive-code .ec-line :where(span[style^='--']:not([class])),:root:not([data-theme='catppuccin-macchiato']) .expressive-code[data-theme='catppuccin-macchiato'] .ec-line :where(span[style^='--']:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}</style><script type="module">try{(()=>{function a(e){if(!e)return;let t=e.getAttribute("tabindex")!==null,r=e.scrollWidth>e.clientWidth;r&&!t?(e.setAttribute("tabindex","0"),e.setAttribute("role","region")):!r&&t&&(e.removeAttribute("tabindex"),e.removeAttribute("role"))}var u=window.requestIdleCallback||(e=>setTimeout(e,1)),s=window.cancelIdleCallback||clearTimeout;function l(e){let t=new Set,r,n;return new ResizeObserver(c=>{c.forEach(o=>t.add(o.target)),r&&clearTimeout(r),n&&s(n),r=setTimeout(()=>{n&&s(n),n=u(()=>{t.forEach(o=>e(o)),t.clear()})},250)})}function i(e,t){e.querySelectorAll?.(".expressive-code pre > code").forEach(r=>{let n=r.parentElement;n&&t.observe(n)})}var d=l(a);i(document,d);var b=new MutationObserver(e=>e.forEach(t=>t.addedNodes.forEach(r=>{i(r,d)})));b.observe(document.body,{childList:!0,subtree:!0});document.addEventListener("astro:page-load",()=>{i(document,d)});})();}catch(e){console.error("[EC] tabindex-js-module failed:",e)}</script><script type="module">try{(()=>{function l(o){let e=document.createElement("pre");Object.assign(e.style,{opacity:"0",pointerEvents:"none",position:"absolute",overflow:"hidden",left:"0",top:"0",width:"20px",height:"20px",webkitUserSelect:"auto",userSelect:"all"}),e.ariaHidden="true",e.textContent=o,document.body.appendChild(e);let a=document.createRange();a.selectNode(e);let n=getSelection();if(!n)return!1;n.removeAllRanges(),n.addRange(a);let r=!1;try{r=document.execCommand("copy")}finally{n.removeAllRanges(),document.body.removeChild(e)}return r}async function u(o){let e=o.currentTarget,a=e.dataset,n=!1,r=a.code.replace(/\u007f/g,`
`);try{await navigator.clipboard.writeText(r),n=!0}catch{n=l(r)}if(!n||e.parentNode?.querySelector(".feedback"))return;let c=e.parentNode?.querySelector("[aria-live]"),t=document.createElement("div");t.classList.add("feedback"),t.append(a.copied),c.append(t),t.offsetWidth,requestAnimationFrame(()=>t?.classList.add("show"));let s=()=>!t||t.classList.remove("show"),d=()=>{!t||parseFloat(getComputedStyle(t).opacity)>0||(t.remove(),t=void 0)};setTimeout(s,1500),setTimeout(d,2500),e.addEventListener("blur",s),t.addEventListener("transitioncancel",d),t.addEventListener("transitionend",d)}function i(o){o.querySelectorAll?.(".expressive-code .copy button").forEach(e=>e.addEventListener("click",u))}i(document);var m=new MutationObserver(o=>o.forEach(e=>e.addedNodes.forEach(a=>{i(a)})));m.observe(document.body,{childList:!0,subtree:!0});document.addEventListener("astro:page-load",()=>{i(document)});})();}catch(e){console.error("[EC] copy-js-module failed:",e)}</script><script type="module">!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).FloatingUICore={})}(this,(function(t){"use strict";const e=["top","right","bottom","left"],n=["start","end"],i=e.reduce(((t,e)=>t.concat(e,e+"-"+n[0],e+"-"+n[1])),[]),o=Math.min,r=Math.max,a={left:"right",right:"left",bottom:"top",top:"bottom"},l={start:"end",end:"start"};function s(t,e,n){return r(t,o(e,n))}function f(t,e){return"function"==typeof t?t(e):t}function c(t){return t.split("-")[0]}function u(t){return t.split("-")[1]}function m(t){return"x"===t?"y":"x"}function d(t){return"y"===t?"height":"width"}function g(t){return["top","bottom"].includes(c(t))?"y":"x"}function p(t){return m(g(t))}function h(t,e,n){void 0===n&&(n=!1);const i=u(t),o=p(t),r=d(o);let a="x"===o?i===(n?"end":"start")?"right":"left":"start"===i?"bottom":"top";return e.reference[r]>e.floating[r]&&(a=w(a)),[a,w(a)]}function y(t){return t.replace(/start|end/g,(t=>l[t]))}function w(t){return t.replace(/left|right|bottom|top/g,(t=>a[t]))}function x(t){return"number"!=typeof t?function(t){return{top:0,right:0,bottom:0,left:0,...t}}(t):{top:t,right:t,bottom:t,left:t}}function v(t){const{x:e,y:n,width:i,height:o}=t;return{width:i,height:o,top:n,left:e,right:e+i,bottom:n+o,x:e,y:n}}function b(t,e,n){let{reference:i,floating:o}=t;const r=g(e),a=p(e),l=d(a),s=c(e),f="y"===r,m=i.x+i.width/2-o.width/2,h=i.y+i.height/2-o.height/2,y=i[l]/2-o[l]/2;let w;switch(s){case"top":w={x:m,y:i.y-o.height};break;case"bottom":w={x:m,y:i.y+i.height};break;case"right":w={x:i.x+i.width,y:h};break;case"left":w={x:i.x-o.width,y:h};break;default:w={x:i.x,y:i.y}}switch(u(e)){case"start":w[a]-=y*(n&&f?-1:1);break;case"end":w[a]+=y*(n&&f?-1:1)}return w}async function A(t,e){var n;void 0===e&&(e={});const{x:i,y:o,platform:r,rects:a,elements:l,strategy:s}=t,{boundary:c="clippingAncestors",rootBoundary:u="viewport",elementContext:m="floating",altBoundary:d=!1,padding:g=0}=f(e,t),p=x(g),h=l[d?"floating"===m?"reference":"floating":m],y=v(await r.getClippingRect({element:null==(n=await(null==r.isElement?void 0:r.isElement(h)))||n?h:h.contextElement||await(null==r.getDocumentElement?void 0:r.getDocumentElement(l.floating)),boundary:c,rootBoundary:u,strategy:s})),w="floating"===m?{x:i,y:o,width:a.floating.width,height:a.floating.height}:a.reference,b=await(null==r.getOffsetParent?void 0:r.getOffsetParent(l.floating)),A=await(null==r.isElement?void 0:r.isElement(b))&&await(null==r.getScale?void 0:r.getScale(b))||{x:1,y:1},R=v(r.convertOffsetParentRelativeRectToViewportRelativeRect?await r.convertOffsetParentRelativeRectToViewportRelativeRect({elements:l,rect:w,offsetParent:b,strategy:s}):w);return{top:(y.top-R.top+p.top)/A.y,bottom:(R.bottom-y.bottom+p.bottom)/A.y,left:(y.left-R.left+p.left)/A.x,right:(R.right-y.right+p.right)/A.x}}function R(t,e){return{top:t.top-e.height,right:t.right-e.width,bottom:t.bottom-e.height,left:t.left-e.width}}function P(t){return e.some((e=>t[e]>=0))}function D(t){const e=o(...t.map((t=>t.left))),n=o(...t.map((t=>t.top)));return{x:e,y:n,width:r(...t.map((t=>t.right)))-e,height:r(...t.map((t=>t.bottom)))-n}}t.arrow=t=>({name:"arrow",options:t,async fn(e){const{x:n,y:i,placement:r,rects:a,platform:l,elements:c,middlewareData:m}=e,{element:g,padding:h=0}=f(t,e)||{};if(null==g)return{};const y=x(h),w={x:n,y:i},v=p(r),b=d(v),A=await l.getDimensions(g),R="y"===v,P=R?"top":"left",D=R?"bottom":"right",T=R?"clientHeight":"clientWidth",O=a.reference[b]+a.reference[v]-w[v]-a.floating[b],E=w[v]-a.reference[v],L=await(null==l.getOffsetParent?void 0:l.getOffsetParent(g));let k=L?L[T]:0;k&&await(null==l.isElement?void 0:l.isElement(L))||(k=c.floating[T]||a.floating[b]);const C=O/2-E/2,B=k/2-A[b]/2-1,H=o(y[P],B),S=o(y[D],B),F=H,j=k-A[b]-S,z=k/2-A[b]/2+C,M=s(F,z,j),V=!m.arrow&&null!=u(r)&&z!==M&&a.reference[b]/2-(z<F?H:S)-A[b]/2<0,W=V?z<F?z-F:z-j:0;return{[v]:w[v]+W,data:{[v]:M,centerOffset:z-M-W,...V&&{alignmentOffset:W}},reset:V}}}),t.autoPlacement=function(t){return void 0===t&&(t={}),{name:"autoPlacement",options:t,async fn(e){var n,o,r;const{rects:a,middlewareData:l,placement:s,platform:m,elements:d}=e,{crossAxis:g=!1,alignment:p,allowedPlacements:w=i,autoAlignment:x=!0,...v}=f(t,e),b=void 0!==p||w===i?function(t,e,n){return(t?[...n.filter((e=>u(e)===t)),...n.filter((e=>u(e)!==t))]:n.filter((t=>c(t)===t))).filter((n=>!t||u(n)===t||!!e&&y(n)!==n))}(p||null,x,w):w,R=await A(e,v),P=(null==(n=l.autoPlacement)?void 0:n.index)||0,D=b[P];if(null==D)return{};const T=h(D,a,await(null==m.isRTL?void 0:m.isRTL(d.floating)));if(s!==D)return{reset:{placement:b[0]}};const O=[R[c(D)],R[T[0]],R[T[1]]],E=[...(null==(o=l.autoPlacement)?void 0:o.overflows)||[],{placement:D,overflows:O}],L=b[P+1];if(L)return{data:{index:P+1,overflows:E},reset:{placement:L}};const k=E.map((t=>{const e=u(t.placement);return[t.placement,e&&g?t.overflows.slice(0,2).reduce(((t,e)=>t+e),0):t.overflows[0],t.overflows]})).sort(((t,e)=>t[1]-e[1])),C=(null==(r=k.filter((t=>t[2].slice(0,u(t[0])?2:3).every((t=>t<=0))))[0])?void 0:r[0])||k[0][0];return C!==s?{data:{index:P+1,overflows:E},reset:{placement:C}}:{}}}},t.computePosition=async(t,e,n)=>{const{placement:i="bottom",strategy:o="absolute",middleware:r=[],platform:a}=n,l=r.filter(Boolean),s=await(null==a.isRTL?void 0:a.isRTL(e));let f=await a.getElementRects({reference:t,floating:e,strategy:o}),{x:c,y:u}=b(f,i,s),m=i,d={},g=0;for(let n=0;n<l.length;n++){const{name:r,fn:p}=l[n],{x:h,y:y,data:w,reset:x}=await p({x:c,y:u,initialPlacement:i,placement:m,strategy:o,middlewareData:d,rects:f,platform:a,elements:{reference:t,floating:e}});c=null!=h?h:c,u=null!=y?y:u,d={...d,[r]:{...d[r],...w}},x&&g<=50&&(g++,"object"==typeof x&&(x.placement&&(m=x.placement),x.rects&&(f=!0===x.rects?await a.getElementRects({reference:t,floating:e,strategy:o}):x.rects),({x:c,y:u}=b(f,m,s))),n=-1)}return{x:c,y:u,placement:m,strategy:o,middlewareData:d}},t.detectOverflow=A,t.flip=function(t){return void 0===t&&(t={}),{name:"flip",options:t,async fn(e){var n,i;const{placement:o,middlewareData:r,rects:a,initialPlacement:l,platform:s,elements:m}=e,{mainAxis:d=!0,crossAxis:p=!0,fallbackPlacements:x,fallbackStrategy:v="bestFit",fallbackAxisSideDirection:b="none",flipAlignment:R=!0,...P}=f(t,e);if(null!=(n=r.arrow)&&n.alignmentOffset)return{};const D=c(o),T=g(l),O=c(l)===l,E=await(null==s.isRTL?void 0:s.isRTL(m.floating)),L=x||(O||!R?[w(l)]:function(t){const e=w(t);return[y(t),e,y(e)]}(l)),k="none"!==b;!x&&k&&L.push(...function(t,e,n,i){const o=u(t);let r=function(t,e,n){const i=["left","right"],o=["right","left"],r=["top","bottom"],a=["bottom","top"];switch(t){case"top":case"bottom":return n?e?o:i:e?i:o;case"left":case"right":return e?r:a;default:return[]}}(c(t),"start"===n,i);return o&&(r=r.map((t=>t+"-"+o)),e&&(r=r.concat(r.map(y)))),r}(l,R,b,E));const C=[l,...L],B=await A(e,P),H=[];let S=(null==(i=r.flip)?void 0:i.overflows)||[];if(d&&H.push(B[D]),p){const t=h(o,a,E);H.push(B[t[0]],B[t[1]])}if(S=[...S,{placement:o,overflows:H}],!H.every((t=>t<=0))){var F,j;const t=((null==(F=r.flip)?void 0:F.index)||0)+1,e=C[t];if(e)return{data:{index:t,overflows:S},reset:{placement:e}};let n=null==(j=S.filter((t=>t.overflows[0]<=0)).sort(((t,e)=>t.overflows[1]-e.overflows[1]))[0])?void 0:j.placement;if(!n)switch(v){case"bestFit":{var z;const t=null==(z=S.filter((t=>{if(k){const e=g(t.placement);return e===T||"y"===e}return!0})).map((t=>[t.placement,t.overflows.filter((t=>t>0)).reduce(((t,e)=>t+e),0)])).sort(((t,e)=>t[1]-e[1]))[0])?void 0:z[0];t&&(n=t);break}case"initialPlacement":n=l}if(o!==n)return{reset:{placement:n}}}return{}}}},t.hide=function(t){return void 0===t&&(t={}),{name:"hide",options:t,async fn(e){const{rects:n}=e,{strategy:i="referenceHidden",...o}=f(t,e);switch(i){case"referenceHidden":{const t=R(await A(e,{...o,elementContext:"reference"}),n.reference);return{data:{referenceHiddenOffsets:t,referenceHidden:P(t)}}}case"escaped":{const t=R(await A(e,{...o,altBoundary:!0}),n.floating);return{data:{escapedOffsets:t,escaped:P(t)}}}default:return{}}}}},t.inline=function(t){return void 0===t&&(t={}),{name:"inline",options:t,async fn(e){const{placement:n,elements:i,rects:a,platform:l,strategy:s}=e,{padding:u=2,x:m,y:d}=f(t,e),p=Array.from(await(null==l.getClientRects?void 0:l.getClientRects(i.reference))||[]),h=function(t){const e=t.slice().sort(((t,e)=>t.y-e.y)),n=[];let i=null;for(let t=0;t<e.length;t++){const o=e[t];!i||o.y-i.y>i.height/2?n.push([o]):n[n.length-1].push(o),i=o}return n.map((t=>v(D(t))))}(p),y=v(D(p)),w=x(u);const b=await l.getElementRects({reference:{getBoundingClientRect:function(){if(2===h.length&&h[0].left>h[1].right&&null!=m&&null!=d)return h.find((t=>m>t.left-w.left&&m<t.right+w.right&&d>t.top-w.top&&d<t.bottom+w.bottom))||y;if(h.length>=2){if("y"===g(n)){const t=h[0],e=h[h.length-1],i="top"===c(n),o=t.top,r=e.bottom,a=i?t.left:e.left,l=i?t.right:e.right;return{top:o,bottom:r,left:a,right:l,width:l-a,height:r-o,x:a,y:o}}const t="left"===c(n),e=r(...h.map((t=>t.right))),i=o(...h.map((t=>t.left))),a=h.filter((n=>t?n.left===i:n.right===e)),l=a[0].top,s=a[a.length-1].bottom;return{top:l,bottom:s,left:i,right:e,width:e-i,height:s-l,x:i,y:l}}return y}},floating:i.floating,strategy:s});return a.reference.x!==b.reference.x||a.reference.y!==b.reference.y||a.reference.width!==b.reference.width||a.reference.height!==b.reference.height?{reset:{rects:b}}:{}}}},t.limitShift=function(t){return void 0===t&&(t={}),{options:t,fn(e){const{x:n,y:i,placement:o,rects:r,middlewareData:a}=e,{offset:l=0,mainAxis:s=!0,crossAxis:u=!0}=f(t,e),d={x:n,y:i},p=g(o),h=m(p);let y=d[h],w=d[p];const x=f(l,e),v="number"==typeof x?{mainAxis:x,crossAxis:0}:{mainAxis:0,crossAxis:0,...x};if(s){const t="y"===h?"height":"width",e=r.reference[h]-r.floating[t]+v.mainAxis,n=r.reference[h]+r.reference[t]-v.mainAxis;y<e?y=e:y>n&&(y=n)}if(u){var b,A;const t="y"===h?"width":"height",e=["top","left"].includes(c(o)),n=r.reference[p]-r.floating[t]+(e&&(null==(b=a.offset)?void 0:b[p])||0)+(e?0:v.crossAxis),i=r.reference[p]+r.reference[t]+(e?0:(null==(A=a.offset)?void 0:A[p])||0)-(e?v.crossAxis:0);w<n?w=n:w>i&&(w=i)}return{[h]:y,[p]:w}}}},t.offset=function(t){return void 0===t&&(t=0),{name:"offset",options:t,async fn(e){var n,i;const{x:o,y:r,placement:a,middlewareData:l}=e,s=await async function(t,e){const{placement:n,platform:i,elements:o}=t,r=await(null==i.isRTL?void 0:i.isRTL(o.floating)),a=c(n),l=u(n),s="y"===g(n),m=["left","top"].includes(a)?-1:1,d=r&&s?-1:1,p=f(e,t);let{mainAxis:h,crossAxis:y,alignmentAxis:w}="number"==typeof p?{mainAxis:p,crossAxis:0,alignmentAxis:null}:{mainAxis:p.mainAxis||0,crossAxis:p.crossAxis||0,alignmentAxis:p.alignmentAxis};return l&&"number"==typeof w&&(y="end"===l?-1*w:w),s?{x:y*d,y:h*m}:{x:h*m,y:y*d}}(e,t);return a===(null==(n=l.offset)?void 0:n.placement)&&null!=(i=l.arrow)&&i.alignmentOffset?{}:{x:o+s.x,y:r+s.y,data:{...s,placement:a}}}}},t.rectToClientRect=v,t.shift=function(t){return void 0===t&&(t={}),{name:"shift",options:t,async fn(e){const{x:n,y:i,placement:o}=e,{mainAxis:r=!0,crossAxis:a=!1,limiter:l={fn:t=>{let{x:e,y:n}=t;return{x:e,y:n}}},...u}=f(t,e),d={x:n,y:i},p=await A(e,u),h=g(c(o)),y=m(h);let w=d[y],x=d[h];if(r){const t="y"===y?"bottom":"right";w=s(w+p["y"===y?"top":"left"],w,w-p[t])}if(a){const t="y"===h?"bottom":"right";x=s(x+p["y"===h?"top":"left"],x,x-p[t])}const v=l.fn({...e,[y]:w,[h]:x});return{...v,data:{x:v.x-n,y:v.y-i,enabled:{[y]:r,[h]:a}}}}}},t.size=function(t){return void 0===t&&(t={}),{name:"size",options:t,async fn(e){var n,i;const{placement:a,rects:l,platform:s,elements:m}=e,{apply:d=(()=>{}),...p}=f(t,e),h=await A(e,p),y=c(a),w=u(a),x="y"===g(a),{width:v,height:b}=l.floating;let R,P;"top"===y||"bottom"===y?(R=y,P=w===(await(null==s.isRTL?void 0:s.isRTL(m.floating))?"start":"end")?"left":"right"):(P=y,R="end"===w?"top":"bottom");const D=b-h.top-h.bottom,T=v-h.left-h.right,O=o(b-h[R],D),E=o(v-h[P],T),L=!e.middlewareData.shift;let k=O,C=E;if(null!=(n=e.middlewareData.shift)&&n.enabled.x&&(C=T),null!=(i=e.middlewareData.shift)&&i.enabled.y&&(k=D),L&&!w){const t=r(h.left,0),e=r(h.right,0),n=r(h.top,0),i=r(h.bottom,0);x?C=v-2*(0!==t||0!==e?t+e:r(h.left,h.right)):k=b-2*(0!==n||0!==i?n+i:r(h.top,h.bottom))}await d({...e,availableWidth:C,availableHeight:k});const B=await s.getDimensions(m.floating);return v!==B.width||b!==B.height?{reset:{rects:!0}}:{}}}}}));</script><script type="module">!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("@floating-ui/core")):"function"==typeof define&&define.amd?define(["exports","@floating-ui/core"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).FloatingUIDOM={},t.FloatingUICore)}(this,(function(t,e){"use strict";const n=Math.min,o=Math.max,i=Math.round,r=Math.floor,c=t=>({x:t,y:t});function l(){return"undefined"!=typeof window}function s(t){return d(t)?(t.nodeName||"").toLowerCase():"#document"}function f(t){var e;return(null==t||null==(e=t.ownerDocument)?void 0:e.defaultView)||window}function u(t){var e;return null==(e=(d(t)?t.ownerDocument:t.document)||window.document)?void 0:e.documentElement}function d(t){return!!l()&&(t instanceof Node||t instanceof f(t).Node)}function a(t){return!!l()&&(t instanceof Element||t instanceof f(t).Element)}function h(t){return!!l()&&(t instanceof HTMLElement||t instanceof f(t).HTMLElement)}function p(t){return!(!l()||"undefined"==typeof ShadowRoot)&&(t instanceof ShadowRoot||t instanceof f(t).ShadowRoot)}function g(t){const{overflow:e,overflowX:n,overflowY:o,display:i}=b(t);return/auto|scroll|overlay|hidden|clip/.test(e+o+n)&&!["inline","contents"].includes(i)}function m(t){return["table","td","th"].includes(s(t))}function y(t){return[":popover-open",":modal"].some((e=>{try{return t.matches(e)}catch(t){return!1}}))}function w(t){const e=x(),n=a(t)?b(t):t;return"none"!==n.transform||"none"!==n.perspective||!!n.containerType&&"normal"!==n.containerType||!e&&!!n.backdropFilter&&"none"!==n.backdropFilter||!e&&!!n.filter&&"none"!==n.filter||["transform","perspective","filter"].some((t=>(n.willChange||"").includes(t)))||["paint","layout","strict","content"].some((t=>(n.contain||"").includes(t)))}function x(){return!("undefined"==typeof CSS||!CSS.supports)&&CSS.supports("-webkit-backdrop-filter","none")}function v(t){return["html","body","#document"].includes(s(t))}function b(t){return f(t).getComputedStyle(t)}function T(t){return a(t)?{scrollLeft:t.scrollLeft,scrollTop:t.scrollTop}:{scrollLeft:t.scrollX,scrollTop:t.scrollY}}function L(t){if("html"===s(t))return t;const e=t.assignedSlot||t.parentNode||p(t)&&t.host||u(t);return p(e)?e.host:e}function R(t){const e=L(t);return v(e)?t.ownerDocument?t.ownerDocument.body:t.body:h(e)&&g(e)?e:R(e)}function C(t,e,n){var o;void 0===e&&(e=[]),void 0===n&&(n=!0);const i=R(t),r=i===(null==(o=t.ownerDocument)?void 0:o.body),c=f(i);if(r){const t=E(c);return e.concat(c,c.visualViewport||[],g(i)?i:[],t&&n?C(t):[])}return e.concat(i,C(i,[],n))}function E(t){return t.parent&&Object.getPrototypeOf(t.parent)?t.frameElement:null}function S(t){const e=b(t);let n=parseFloat(e.width)||0,o=parseFloat(e.height)||0;const r=h(t),c=r?t.offsetWidth:n,l=r?t.offsetHeight:o,s=i(n)!==c||i(o)!==l;return s&&(n=c,o=l),{width:n,height:o,$:s}}function F(t){return a(t)?t:t.contextElement}function O(t){const e=F(t);if(!h(e))return c(1);const n=e.getBoundingClientRect(),{width:o,height:r,$:l}=S(e);let s=(l?i(n.width):n.width)/o,f=(l?i(n.height):n.height)/r;return s&&Number.isFinite(s)||(s=1),f&&Number.isFinite(f)||(f=1),{x:s,y:f}}const D=c(0);function H(t){const e=f(t);return x()&&e.visualViewport?{x:e.visualViewport.offsetLeft,y:e.visualViewport.offsetTop}:D}function P(t,n,o,i){void 0===n&&(n=!1),void 0===o&&(o=!1);const r=t.getBoundingClientRect(),l=F(t);let s=c(1);n&&(i?a(i)&&(s=O(i)):s=O(t));const u=function(t,e,n){return void 0===e&&(e=!1),!(!n||e&&n!==f(t))&&e}(l,o,i)?H(l):c(0);let d=(r.left+u.x)/s.x,h=(r.top+u.y)/s.y,p=r.width/s.x,g=r.height/s.y;if(l){const t=f(l),e=i&&a(i)?f(i):i;let n=t,o=E(n);for(;o&&i&&e!==n;){const t=O(o),e=o.getBoundingClientRect(),i=b(o),r=e.left+(o.clientLeft+parseFloat(i.paddingLeft))*t.x,c=e.top+(o.clientTop+parseFloat(i.paddingTop))*t.y;d*=t.x,h*=t.y,p*=t.x,g*=t.y,d+=r,h+=c,n=f(o),o=E(n)}}return e.rectToClientRect({width:p,height:g,x:d,y:h})}function W(t,e){const n=T(t).scrollLeft;return e?e.left+n:P(u(t)).left+n}function M(t,e,n){void 0===n&&(n=!1);const o=t.getBoundingClientRect();return{x:o.left+e.scrollLeft-(n?0:W(t,o)),y:o.top+e.scrollTop}}function z(t,n,i){let r;if("viewport"===n)r=function(t,e){const n=f(t),o=u(t),i=n.visualViewport;let r=o.clientWidth,c=o.clientHeight,l=0,s=0;if(i){r=i.width,c=i.height;const t=x();(!t||t&&"fixed"===e)&&(l=i.offsetLeft,s=i.offsetTop)}return{width:r,height:c,x:l,y:s}}(t,i);else if("document"===n)r=function(t){const e=u(t),n=T(t),i=t.ownerDocument.body,r=o(e.scrollWidth,e.clientWidth,i.scrollWidth,i.clientWidth),c=o(e.scrollHeight,e.clientHeight,i.scrollHeight,i.clientHeight);let l=-n.scrollLeft+W(t);const s=-n.scrollTop;return"rtl"===b(i).direction&&(l+=o(e.clientWidth,i.clientWidth)-r),{width:r,height:c,x:l,y:s}}(u(t));else if(a(n))r=function(t,e){const n=P(t,!0,"fixed"===e),o=n.top+t.clientTop,i=n.left+t.clientLeft,r=h(t)?O(t):c(1);return{width:t.clientWidth*r.x,height:t.clientHeight*r.y,x:i*r.x,y:o*r.y}}(n,i);else{const e=H(t);r={x:n.x-e.x,y:n.y-e.y,width:n.width,height:n.height}}return e.rectToClientRect(r)}function A(t,e){const n=L(t);return!(n===e||!a(n)||v(n))&&("fixed"===b(n).position||A(n,e))}function V(t,e,n){const o=h(e),i=u(e),r="fixed"===n,l=P(t,!0,r,e);let f={scrollLeft:0,scrollTop:0};const d=c(0);if(o||!o&&!r)if(("body"!==s(e)||g(i))&&(f=T(e)),o){const t=P(e,!0,r,e);d.x=t.x+e.clientLeft,d.y=t.y+e.clientTop}else i&&(d.x=W(i));const a=!i||o||r?c(0):M(i,f);return{x:l.left+f.scrollLeft-d.x-a.x,y:l.top+f.scrollTop-d.y-a.y,width:l.width,height:l.height}}function B(t){return"static"===b(t).position}function N(t,e){if(!h(t)||"fixed"===b(t).position)return null;if(e)return e(t);let n=t.offsetParent;return u(t)===n&&(n=n.ownerDocument.body),n}function I(t,e){const n=f(t);if(y(t))return n;if(!h(t)){let e=L(t);for(;e&&!v(e);){if(a(e)&&!B(e))return e;e=L(e)}return n}let o=N(t,e);for(;o&&m(o)&&B(o);)o=N(o,e);return o&&v(o)&&B(o)&&!w(o)?n:o||function(t){let e=L(t);for(;h(e)&&!v(e);){if(w(e))return e;if(y(e))return null;e=L(e)}return null}(t)||n}const k={convertOffsetParentRelativeRectToViewportRelativeRect:function(t){let{elements:e,rect:n,offsetParent:o,strategy:i}=t;const r="fixed"===i,l=u(o),f=!!e&&y(e.floating);if(o===l||f&&r)return n;let d={scrollLeft:0,scrollTop:0},a=c(1);const p=c(0),m=h(o);if((m||!m&&!r)&&(("body"!==s(o)||g(l))&&(d=T(o)),h(o))){const t=P(o);a=O(o),p.x=t.x+o.clientLeft,p.y=t.y+o.clientTop}const w=!l||m||r?c(0):M(l,d,!0);return{width:n.width*a.x,height:n.height*a.y,x:n.x*a.x-d.scrollLeft*a.x+p.x+w.x,y:n.y*a.y-d.scrollTop*a.y+p.y+w.y}},getDocumentElement:u,getClippingRect:function(t){let{element:e,boundary:i,rootBoundary:r,strategy:c}=t;const l=[..."clippingAncestors"===i?y(e)?[]:function(t,e){const n=e.get(t);if(n)return n;let o=C(t,[],!1).filter((t=>a(t)&&"body"!==s(t))),i=null;const r="fixed"===b(t).position;let c=r?L(t):t;for(;a(c)&&!v(c);){const e=b(c),n=w(c);n||"fixed"!==e.position||(i=null),(r?!n&&!i:!n&&"static"===e.position&&i&&["absolute","fixed"].includes(i.position)||g(c)&&!n&&A(t,c))?o=o.filter((t=>t!==c)):i=e,c=L(c)}return e.set(t,o),o}(e,this._c):[].concat(i),r],f=l[0],u=l.reduce(((t,i)=>{const r=z(e,i,c);return t.top=o(r.top,t.top),t.right=n(r.right,t.right),t.bottom=n(r.bottom,t.bottom),t.left=o(r.left,t.left),t}),z(e,f,c));return{width:u.right-u.left,height:u.bottom-u.top,x:u.left,y:u.top}},getOffsetParent:I,getElementRects:async function(t){const e=this.getOffsetParent||I,n=this.getDimensions,o=await n(t.floating);return{reference:V(t.reference,await e(t.floating),t.strategy),floating:{x:0,y:0,width:o.width,height:o.height}}},getClientRects:function(t){return Array.from(t.getClientRects())},getDimensions:function(t){const{width:e,height:n}=S(t);return{width:e,height:n}},getScale:O,isElement:a,isRTL:function(t){return"rtl"===b(t).direction}};const q=e.detectOverflow,U=e.offset,j=e.autoPlacement,X=e.shift,Y=e.flip,$=e.size,_=e.hide,G=e.arrow,J=e.inline,K=e.limitShift;t.arrow=G,t.autoPlacement=j,t.autoUpdate=function(t,e,i,c){void 0===c&&(c={});const{ancestorScroll:l=!0,ancestorResize:s=!0,elementResize:f="function"==typeof ResizeObserver,layoutShift:d="function"==typeof IntersectionObserver,animationFrame:a=!1}=c,h=F(t),p=l||s?[...h?C(h):[],...C(e)]:[];p.forEach((t=>{l&&t.addEventListener("scroll",i,{passive:!0}),s&&t.addEventListener("resize",i)}));const g=h&&d?function(t,e){let i,c=null;const l=u(t);function s(){var t;clearTimeout(i),null==(t=c)||t.disconnect(),c=null}return function f(u,d){void 0===u&&(u=!1),void 0===d&&(d=1),s();const{left:a,top:h,width:p,height:g}=t.getBoundingClientRect();if(u||e(),!p||!g)return;const m={rootMargin:-r(h)+"px "+-r(l.clientWidth-(a+p))+"px "+-r(l.clientHeight-(h+g))+"px "+-r(a)+"px",threshold:o(0,n(1,d))||1};let y=!0;function w(t){const e=t[0].intersectionRatio;if(e!==d){if(!y)return f();e?f(!1,e):i=setTimeout((()=>{f(!1,1e-7)}),1e3)}y=!1}try{c=new IntersectionObserver(w,{...m,root:l.ownerDocument})}catch(t){c=new IntersectionObserver(w,m)}c.observe(t)}(!0),s}(h,i):null;let m,y=-1,w=null;f&&(w=new ResizeObserver((t=>{let[n]=t;n&&n.target===h&&w&&(w.unobserve(e),cancelAnimationFrame(y),y=requestAnimationFrame((()=>{var t;null==(t=w)||t.observe(e)}))),i()})),h&&!a&&w.observe(h),w.observe(e));let x=a?P(t):null;return a&&function e(){const n=P(t);!x||n.x===x.x&&n.y===x.y&&n.width===x.width&&n.height===x.height||i();x=n,m=requestAnimationFrame(e)}(),i(),()=>{var t;p.forEach((t=>{l&&t.removeEventListener("scroll",i),s&&t.removeEventListener("resize",i)})),null==g||g(),null==(t=w)||t.disconnect(),w=null,a&&cancelAnimationFrame(m)}},t.computePosition=(t,n,o)=>{const i=new Map,r={platform:k,...o},c={...r.platform,_c:i};return e.computePosition(t,n,{...r,platform:c})},t.detectOverflow=q,t.flip=Y,t.getOverflowAncestors=C,t.hide=_,t.inline=J,t.limitShift=K,t.offset=U,t.platform=k,t.shift=X,t.size=$}));</script><script type="module">function setupTooltip(e,o){let s=e.querySelector(".twoslash-popup-container"),t=s.closest(".expressive-code"),i="twoslash_popup_"+[Math.random(),Date.now()].map(e=>e.toString(36).substring(2,10)).join("_");s.setAttribute("role","tooltip"),s.setAttribute("tabindex","-1"),s?.parentNode&&s.parentNode.removeChild(s);let a=!1,r;function n(){clearTimeout(r),t.appendChild(s),new Promise(e=>requestAnimationFrame(()=>{requestAnimationFrame(e)})).then(()=>FloatingUIDOM.computePosition(e,s,{placement:o?"bottom":"bottom-start",middleware:[FloatingUIDOM.size({apply({availableWidth:e}){Object.assign(s.style,{maxWidth:Math.max(300,e)+"px",maxHeight:"100%"})}})]})).then(({x:e,y:t})=>{Object.assign(s.style,{display:"block",left:`${o?20:e}px`,top:t+"px"})}),s.setAttribute("aria-hidden","false"),e.querySelector(".twoslash-hover span")?.setAttribute("aria-describedby",i),s.setAttribute("id",i)}function d(){s.setAttribute("aria-hidden","true"),e.querySelector(".twoslash-hover span")?.removeAttribute("aria-describedby"),s.removeAttribute("id"),s.style.display="none"}e.addEventListener("mouseenter",n),e.addEventListener("mouseleave",()=>{r=setTimeout(()=>{a||d()},100)}),s.addEventListener("mouseenter",()=>{clearTimeout(r),a=!0}),s.addEventListener("mouseleave",()=>{a=!1,r=setTimeout(()=>{e.matches(":hover")||d()},100)}),e.addEventListener("focus",n),e.addEventListener("blur",d),d()}let isMobileScreen=window.matchMedia("(max-width: 500px)").matches;function initTwoslashPopups(e){e.querySelectorAll?.(".twoslash-hover").forEach(e=>{setupTooltip(e,isMobileScreen)})}initTwoslashPopups(document);let newTwoslashPopupObserver=new MutationObserver(e=>e.forEach(e=>e.addedNodes.forEach(e=>{initTwoslashPopups(e)})));newTwoslashPopupObserver.observe(document.body,{childList:!0,subtree:!0}),document.addEventListener("astro:page-load",()=>{initTwoslashPopups(document.body)});</script><figure class="frame is-terminal"><figcaption class="header"><span class="title"></span><span class="sr-only">Terminal window</span></figcaption><pre data-language="bash"><code><div class="ec-line"><div class="code"><span style="--0:#8AADF4;--0fs:italic">npx</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">degit</span><span style="--0:#CAD3F5"> </span><mark><span style="--0:#A6DA95">usuario</span></mark><span style="--0:#A6DA95">/</span><mark><span style="--0:#A6DA95">repositorio</span></mark><span style="--0:#A6DA95">/</span><mark><span style="--0:#A6DA95">caminho</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">para</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">pasta</span></mark><span style="--0:#A6DA95">#</span><mark><span style="--0:#A6DA95">branch</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">ou</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">tag</span></mark><span style="--0:#CAD3F5"> </span><mark><span style="--0:#A6DA95">destino</span></mark></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="npx degit usuario/repositorio/caminho para pasta#branch ou tag destino"><div></div></button></div></figure></div>
<h2 id="3-usando-o-git-sparse-checkout-nativo"><a class="anchor-link" aria-hidden tabindex="-1" href="#3-usando-o-git-sparse-checkout-nativo">#</a>3. Usando o Git Sparse Checkout (nativo)</h2>
<p>Esse método não é tão simples quanto os anteriores, mas o git tem uma funcionalidade nativa e robusta para essa finalidade, chamada Sparse Checkout. Diferente do Degit, esse método vai baixar apenas os metadados (estrutura de pastas, etc) e os arquivos que você especificar. Basta executar os comandos abaixo:</p>
<div class="expressive-code"><figure class="frame is-terminal"><figcaption class="header"><span class="title"></span><span class="sr-only">Terminal window</span></figcaption><pre data-language="bash"><code><div class="ec-line"><div class="code"><span style="--0:#8AADF4;--0fs:italic">git</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">clone</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">--filter=blob:none</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">--no-checkout</span><span style="--0:#CAD3F5"> </span><mark><span style="--0:#A6DA95">url</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">do</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">repositorio</span></mark></div></div><div class="ec-line"><div class="code">
</div></div><div class="ec-line"><div class="code"><span style="--0:#ED8796;--0fs:italic">cd</span><span style="--0:#CAD3F5"> </span><mark><span style="--0:#A6DA95">pasta</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">do</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">repositorio</span></mark></div></div><div class="ec-line"><div class="code">
</div></div><div class="ec-line"><div class="code"><span style="--0:#8AADF4;--0fs:italic">git</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">sparse-checkout</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">init</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">--cone</span></div></div><div class="ec-line"><div class="code">
</div></div><div class="ec-line"><div class="code"><span style="--0:#8AADF4;--0fs:italic">git</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">sparse-checkout</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">set</span><span style="--0:#CAD3F5"> </span><mark><span style="--0:#A6DA95">caminho</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">da</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">pasta</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">que</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">você</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">quer</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">baixar</span></mark></div></div><div class="ec-line"><div class="code">
</div></div><div class="ec-line"><div class="code"><span style="--0:#8AADF4;--0fs:italic">git</span><span style="--0:#CAD3F5"> </span><span style="--0:#A6DA95">checkout</span><span style="--0:#CAD3F5"> </span><mark><span style="--0:#A6DA95">branch</span></mark></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="git clone --filter=blob:none --no-checkout url do repositoriocd pasta do repositoriogit sparse-checkout init --conegit sparse-checkout set caminho da pasta que você quer baixargit checkout branch"><div></div></button></div></figure></div>
<hr>
<div class="alert alert-info" role="alert"><div><p>PS: Essa é minha primeira postagem. O plano era que o primeiro post fosse sobre como eu criei este blog utilizando SvelteKit e Markdown (que será publicado em breve). Mas tive a necessidade de disponibilizar o código que eu vou escrever nos artigos de maneira simples, já que todo o código e conteúdo está hospedado em um único <a href="https://github.com/vadolasi/site" target="_blank">repositório público</a>, então decidi escrever este post primeiro.</p>
</div></div>]]></content>
        <author>
            <name>Vitor Daniel</name>
            <email>vitor@vitordaniel.is-a.dev</email>
            <uri>https://vitordaniel.is-a.dev</uri>
        </author>
        <published>2026-01-11T02:38:21.000Z</published>
        <rights>© 2026 Vitor Daniel</rights>
    </entry>
</feed>