<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>@lcmartinsfilho’s Blog do Luiz - Categories</title><link>https://luizmartins.dev/https://luizmartins.dev/categories/</link><description>All entries in Categories on Blog do Luiz</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><atom:link href="https://luizmartins.dev/categories/" rel="self" type="application/rss+xml"/><item><title>Testando a criação de posts no iPad (segunda vez)</title><link>https://luizmartins.dev/post/second-ipad-post/</link><pubDate>Thu, 10 Sep 2026 23:23:00 +0000</pubDate><author>Luiz Carlos Martins Filho</author><guid>https://luizmartins.dev/post/second-ipad-post/</guid><description>&lt;p&gt;Dessa vez clonei o repo do meu Github Pages dentro do iSH e editei o arquivo diretamente no terminal pelo neovim, commitei e pushei para o repo. Me pareceu muito mais ergonômico e prático do que usar a interface do Github, sem falar que funciona completamente off-line.&lt;/p&gt;</description></item><item><title>Testando a criação de posts no iPad</title><link>https://luizmartins.dev/post/posting-from-ipad/</link><pubDate>Thu, 10 Sep 2026 23:00:00 +0000</pubDate><author>Luiz Carlos Martins Filho</author><guid>https://luizmartins.dev/post/posting-from-ipad/</guid><description>&lt;p&gt;Estou na academia, num café próximo à entrada, testando a viabilidade de criar posts em meu blog usando o iPad com o teclado. Se o app do Github não funcionar ou não for ergonômico o suficiente, ainda posso testar o iSH ou coisa parecida para fazer modificações locais. Aliás, acho que clonar o repositório do blog por lá e usar o neovim talvez seja a alternativa mais interessante.&lt;/p&gt;
&lt;p&gt;Esse post escrevi dentro do próprio app do Github, criando o arquivo diretamente nele e commitando diretamente na main.&lt;/p&gt;</description></item><item><title>Correção de texto com Harper</title><link>https://luizmartins.dev/post/correcao-de-texto-com-harper/</link><pubDate>Sun, 18 Jan 2026 00:00:00 +0000</pubDate><author>Luiz Carlos Martins Filho</author><guid>https://luizmartins.dev/post/correcao-de-texto-com-harper/</guid><description>&lt;p&gt;Luiz recentemente recebeu uma recomendação sobre &lt;a href="https://writewithharper.com/"&gt;Harper&lt;/a&gt;, uma nova ferramenta de verificação gramatical desenvolvida pela &lt;a href="https://automattic.com/"&gt;Automattic&lt;/a&gt; usando Rust.&lt;/p&gt;
&lt;p&gt;O repositório do projeto descreve Harper como atendendo aos requisitos específicos do desenvolvedor: ele é o verificador gramatical que atende às necessidades, analisando documentos em milissegundos com um consumo mínimo de memória.&lt;/p&gt;
&lt;h2 id="características-principais"&gt;Características principais&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Desempenho rápido:&lt;/strong&gt; análise em nível de milissegundos&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Baixo consumo de memória:&lt;/strong&gt; menos de 1/50 do uso do LanguageTool&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Privacidade completa:&lt;/strong&gt; funciona localmente, sem enviar dados para servidores&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compatibilidade com WebAssembly:&lt;/strong&gt; pode ser executado em múltiplas plataformas&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="image-1.png" alt="Harper Interface"&gt;&lt;/p&gt;
&lt;h2 id="instalação"&gt;Instalação&lt;/h2&gt;
&lt;p&gt;A instalação é simples através das lojas de extensões para:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navegadores web&lt;/li&gt;
&lt;li&gt;Visual Studio Code&lt;/li&gt;
&lt;li&gt;Obsidian&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Para outras plataformas, documentação abrangente está disponível em &lt;a href="https://writewithharper.com/docs/about"&gt;writewithharper.com/docs/about&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="screenshot.png" alt="Plataformas Disponíveis"&gt;&lt;/p&gt;
&lt;h2 id="links-úteis"&gt;Links úteis&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://writewithharper.com/"&gt;Site Oficial - Harper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Automattic/harper"&gt;Repositório no GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://writewithharper.com/docs/about"&gt;Documentação Oficial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Sincronizando seu Obsidian</title><link>https://luizmartins.dev/post/instalando-obsidian-sync/</link><pubDate>Sat, 17 Jan 2026 14:15:00 +0000</pubDate><author>Luiz Carlos Martins Filho</author><guid>https://luizmartins.dev/post/instalando-obsidian-sync/</guid><description>&lt;p&gt;Existem várias formas de sincronizar o Obsidian, mas decidi documentar o método que escolhi, tanto para não esquecer os detalhes no futuro quanto para ajudar quem também busca uma solução própria de sincronização.&lt;/p&gt;
&lt;p&gt;Para esse projeto, usaremos o plugin Obsidian LiveSync:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/vrtmrz/obsidian-livesync"&gt;vrtmrz/obsidian-livesync&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="criando-uma-vps-no-magalucloud"&gt;Criando uma VPS no MagaluCloud&lt;/h2&gt;
&lt;p&gt;Para o servidor, criarei uma VPS no &lt;a href="https://magalu.cloud/?ref=luizmartins.dev"&gt;MagaluCloud&lt;/a&gt;. Vou fazer o mesmo processo de forma manual, pelo console, mas é possível fazer tudo utilizando o &lt;code&gt;mgc&lt;/code&gt; (MagaluCloud &lt;em&gt;cli&lt;/em&gt;).&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Abra o &lt;a href="https://console.magalu.cloud/?ref=luizmartins.dev"&gt;console&lt;/a&gt;. Para criar uma nova máquina virtual, clique em &lt;a href="https://console.magalu.cloud/virtual-machine?ref=luizmartins.dev"&gt;Virtual Machines&lt;/a&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="1-abrindo-vm.png" alt="Abrindo Virtual Machines no console"&gt;&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Na página de &lt;a href="https://console.magalu.cloud/virtual-machine?ref=luizmartins.dev"&gt;Virtual Machines&lt;/a&gt;, clique em &lt;strong&gt;Criar Instância&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="2-criar-instancia.png" alt="Clicando em Criar Instância"&gt;&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Selecione a Zona de Disponibilidade desejada (nesse exemplo, escolhi a br-se1-a) e também o Sistema Operacional. Aqui vou de Debian 13 LTS:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="3-zona-distro.png" alt="Selecionando zona e sistema operacional"&gt;&lt;/p&gt;
&lt;p&gt;Para o servidor, podemos ir com a opção mais barata! Escolhi a instância com 1 vCPU e 1 GB de RAM (BV1-1-20). O único detalhe é o espaço; por segurança, escolhi um disco local de 20 GB.&lt;/p&gt;
&lt;p&gt;&lt;img src="4-dimensionamento-maquina.png" alt="Dimensionamento e configuração da máquina"&gt;&lt;/p&gt;
&lt;p&gt;Não se esqueça de deixar marcada a opção para atribuir endereço de IPv4 público para a instância. Para acessar a máquina, selecione uma chave SSH existente (se já tiver uma). Do contrário, insira uma chave pública nova. Se não ainda não tiver uma, a documentação pode ajudar. Guarde as chaves geradas com cuidado, pois perdê-las impedirá o acesso à máquina! Por fim, dê um nome ilustrativo à instância e clique em Criar instância.&lt;/p&gt;
&lt;p&gt;&lt;img src="5-ip-nomeia-maquina.png" alt="Configurando IP e nomeando a máquina"&gt;&lt;/p&gt;
&lt;h2 id="configurando-o-servidor"&gt;Configurando o servidor&lt;/h2&gt;
&lt;p&gt;Acesse o servidor recém criado com ssh:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh debian@seu-ip-aqui.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Para esse projeto, precisaremos do Docker instalado. O passo a passo de instalação foi retirado da documentação do projeto. Rode individualmente cada comando abaixo para adicionar o repositório do Docker ao seu servidor:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Add Docker&amp;#39;s official GPG key:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install ca-certificates curl
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo install -m &lt;span class="m"&gt;0755&lt;/span&gt; -d /etc/apt/keyrings
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chmod a+r /etc/apt/keyrings/docker.asc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Add the repository to Apt sources:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo tee /etc/apt/sources.list.d/docker.sources &lt;span class="s"&gt;&amp;lt;&amp;lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;Types: deb
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;URIs: https://download.docker.com/linux/debian
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;Suites: $(. /etc/os-release &amp;amp;&amp;amp; echo &amp;#34;$VERSION_CODENAME&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;Components: stable
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;Signed-By: /etc/apt/keyrings/docker.asc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Depois de adicionar o repositório oficial do Docker com os comandos acima, instale as ferramentas necessárias:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Com o Docker instalado, crie um diretório para separar seus dados e configurações:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p ~/obsidian-livesync/&lt;span class="o"&gt;{&lt;/span&gt;couchdb-data,config&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/obsidian-livesync
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Crie o arquivo &lt;code&gt;~/obsidian-livesync/config/local.ini&lt;/code&gt; e adicione as seguintes configurações:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[couchdb]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;single_node&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;max_document_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;50000000 ; 50MB (Adjust based on your note size needs)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[chttpd]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;require_valid_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;max_http_request_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;4294967296 ; 4GB (Necessary for large sync batches)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;enable_cors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[chttpd_auth]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;require_valid_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;authentication_redirect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;/_utils/session.html&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[httpd]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;WWW-Authenticate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Basic realm=&amp;#34;administrator&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;enable_cors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[cors]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;origins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;app://obsidian.md,capacitor://localhost,http://localhost&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;accept, authorization, content-type, origin, referer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;methods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;GET, PUT, POST, HEAD, DELETE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;max_age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;3600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Para instalar o CouchDB, usaremos um docker compose:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3.8&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;couchdb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;couchdb:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;livesync-couchdb&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;always&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;COUCHDB_USER=admin&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;COUCHDB_PASSWORD=YOUR_STRONG_PASSWORD_HERE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./couchdb-data:/opt/couchdb/data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./config/local.ini:/opt/couchdb/etc/local.d/local.ini&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;127.0.0.1:5984:5984&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Expose only to localhost, Caddy handles external traffic&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;caddy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;caddy:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;livesync-caddy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;always&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;80:80&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;443:443&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./Caddyfile:/etc/caddy/Caddyfile&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;caddy_data:/data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;caddy_config:/config&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;couchdb&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;caddy_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;caddy_config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Não se esqueça de alterar a senha de seu banco no arquivo anterior. Escolha uma senha forte!&lt;/p&gt;
&lt;p&gt;Para lidar com proxy reverso e certificado digital, usaremos o Caddy. Crie o arquivo &lt;code&gt;~/obsidian-livesync/Caddyfile&lt;/code&gt; e adicione as seguintes configurações, ajustando o domínio:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;obsidian.yourdomain.com {
reverse_proxy couchdb:5984
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Suba a stack com:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Agora vamos criar um banco de dados chamado obsidian. Você é livre para usar qualquer nome aqui:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -X PUT -u admin http://127.0.0.1:5984/obsidian
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Entre com o nome de usuário e senha definidos no arquivo &lt;code&gt;~/obsidian-livesync/config/local.ini&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="configurando-o-cliente"&gt;Configurando o cliente&lt;/h2&gt;
&lt;p&gt;Instale o Plugin Self-hosted LiveSync após ativar os Community Plugins.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setup Wizard:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Abra as Plugin Settings&lt;/li&gt;
&lt;li&gt;Selecione Remote Database Configuration&lt;/li&gt;
&lt;li&gt;Configure os seguintes campos:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;URI:&lt;/strong&gt; &lt;a href="https://obsidian.yourdomain.com"&gt;https://obsidian.yourdomain.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Username:&lt;/strong&gt; admin&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Password:&lt;/strong&gt; YOUR_STRONG_PASSWORD_HERE&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database Name:&lt;/strong&gt; obsidian&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;End-to-End Encryption:&lt;/strong&gt; Enabled (Recomendado! Será usada uma nova senha para encriptação!)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Teste: Clique &amp;ldquo;Test Connection&amp;rdquo;. Se tiver sucesso, aplique as configurações.&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Tips for Contributing to Open Source</title><link>https://luizmartins.dev/post/open-source-contribution-tips/</link><pubDate>Wed, 01 Oct 2025 09:45:00 +0000</pubDate><author>Luiz Carlos Martins Filho</author><guid>https://luizmartins.dev/post/open-source-contribution-tips/</guid><description>&lt;h2 id="tips-for-contributing-to-open-source"&gt;Tips for Contributing to Open Source&lt;/h2&gt;
&lt;p&gt;Open-source contributions are rewarding, but can feel intimidating. Here are practical tips for making meaningful contributions.&lt;/p&gt;
&lt;h3 id="start-small"&gt;Start Small&lt;/h3&gt;
&lt;p&gt;Don&amp;rsquo;t try to solve the hardest problems first:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Look for issues labeled &lt;code&gt;good first issue&lt;/code&gt; or &lt;code&gt;help wanted&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Fix typos and improve documentation&lt;/li&gt;
&lt;li&gt;Add tests for existing functionality&lt;/li&gt;
&lt;li&gt;Improve error messages&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="read-the-guidelines"&gt;Read the Guidelines&lt;/h3&gt;
&lt;p&gt;Every project has contribution guidelines. Read them!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CONTRIBUTING.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CODE_OF_CONDUCT.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PULL_REQUEST_TEMPLATE.md&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Understanding these saves time for both you and maintainers.&lt;/p&gt;
&lt;h3 id="communicate-early"&gt;Communicate Early&lt;/h3&gt;
&lt;p&gt;Before investing significant time, discuss your approach:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Interested in tackling &lt;span class="ni"&gt;#123&lt;/span&gt;. Here&amp;#39;s my plan:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;1.&lt;/span&gt; Refactor X to use Y approach
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;2.&lt;/span&gt; Add tests for edge cases
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;3.&lt;/span&gt; Update documentation
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Does this align with the project&amp;#39;s direction?
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="write-good-commits"&gt;Write Good Commits&lt;/h3&gt;
&lt;p&gt;Clear commits help maintainers review your code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Add caching layer to improve performance
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Implement LRU cache for frequently accessed data
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Add cache configuration options
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Include benchmarks showing 40% improvement
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Update documentation with caching details
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Fixes #456
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="test-your-changes"&gt;Test Your Changes&lt;/h3&gt;
&lt;p&gt;Ensure your code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ Passes existing tests&lt;/li&gt;
&lt;li&gt;✅ Includes new tests for new features&lt;/li&gt;
&lt;li&gt;✅ Works on different platforms/versions&lt;/li&gt;
&lt;li&gt;✅ Doesn&amp;rsquo;t introduce performance regressions&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="be-patient-and-respectful"&gt;Be Patient and Respectful&lt;/h3&gt;
&lt;p&gt;Maintainers are volunteers. They may take time to review:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Follow up respectfully after a week&lt;/li&gt;
&lt;li&gt;Address feedback promptly&lt;/li&gt;
&lt;li&gt;Don&amp;rsquo;t take rejection personally&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="tools-and-resources"&gt;Tools and Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.firsttimersonly.com/"&gt;First Timers Only&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://goodfirstissue.dev/"&gt;Good First Issues&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opensource.guide/"&gt;Open Source Guides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="your-first-pr"&gt;Your First PR&lt;/h3&gt;
&lt;p&gt;Remember: everyone started with their first contribution. Take that step, and you&amp;rsquo;ll be amazed at how welcoming the community can be!&lt;/p&gt;</description></item><item><title>Building CLI Tools That Users Love</title><link>https://luizmartins.dev/post/building-cli-tools/</link><pubDate>Mon, 22 Sep 2025 14:15:00 +0000</pubDate><author>Luiz Carlos Martins Filho</author><guid>https://luizmartins.dev/post/building-cli-tools/</guid><description>&lt;h2 id="building-cli-tools-that-users-love"&gt;Building CLI Tools That Users Love&lt;/h2&gt;
&lt;p&gt;Command-line tools are a developer&amp;rsquo;s best friend. A well-designed CLI can significantly improve productivity and developer experience. Here are some best practices.&lt;/p&gt;
&lt;h3 id="principle-1-clear-help-text"&gt;Principle 1: Clear Help Text&lt;/h3&gt;
&lt;p&gt;Always provide comprehensive help documentation:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mytool --help
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Usage: mytool &lt;span class="o"&gt;[&lt;/span&gt;OPTIONS&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;COMMAND&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;A powerful CLI tool &lt;span class="k"&gt;for&lt;/span&gt; developers
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Commands:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; build Build your project
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;test&lt;/span&gt; Run tests
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; deploy Deploy to production
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;help&lt;/span&gt; Print this message
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Options:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -h, --help Print &lt;span class="nb"&gt;help&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -v, --version Print version
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="principle-2-sensible-defaults"&gt;Principle 2: Sensible Defaults&lt;/h3&gt;
&lt;p&gt;Users shouldn&amp;rsquo;t need to specify every option. Use smart defaults:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Good - works with sensible defaults&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mytool build
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Still flexible - can override defaults&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mytool build --target release --jobs &lt;span class="m"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="principle-3-useful-error-messages"&gt;Principle 3: Useful Error Messages&lt;/h3&gt;
&lt;p&gt;Error messages should guide users toward solutions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Error: Config file not found at ~/.mytool/config.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Did you mean to:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1. Create a config: mytool init
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 2. Specify a custom path: mytool --config /path/to/config.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="principle-4-progress-feedback"&gt;Principle 4: Progress Feedback&lt;/h3&gt;
&lt;p&gt;Long-running operations should provide feedback:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mytool deploy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;████████░░&lt;span class="o"&gt;]&lt;/span&gt; Building... &lt;span class="o"&gt;(&lt;/span&gt;60%&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;██████████&lt;span class="o"&gt;]&lt;/span&gt; Testing... &lt;span class="o"&gt;(&lt;/span&gt;100%&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;██████████&lt;span class="o"&gt;]&lt;/span&gt; Deploying... &lt;span class="o"&gt;(&lt;/span&gt;100%&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;✓ Deployment successful
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="tool-recommendations"&gt;Tool Recommendations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rust&lt;/strong&gt;: &lt;code&gt;clap&lt;/code&gt; for argument parsing, &lt;code&gt;indicatif&lt;/code&gt; for progress bars&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python&lt;/strong&gt;: &lt;code&gt;click&lt;/code&gt; or &lt;code&gt;typer&lt;/code&gt; for CLI frameworks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Go&lt;/strong&gt;: &lt;code&gt;cobra&lt;/code&gt; or &lt;code&gt;urfave/cli&lt;/code&gt; for CLI applications&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Great CLI tools are invisible—users can accomplish their goals without thinking about the tool itself. Focus on clarity, consistency, and helpful feedback.&lt;/p&gt;</description></item><item><title>Getting Started with Rust</title><link>https://luizmartins.dev/post/getting-started-with-rust/</link><pubDate>Mon, 15 Sep 2025 10:30:00 +0000</pubDate><author>Luiz Carlos Martins Filho</author><guid>https://luizmartins.dev/post/getting-started-with-rust/</guid><description>&lt;h2 id="getting-started-with-rust"&gt;Getting Started with Rust&lt;/h2&gt;
&lt;p&gt;Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety. In this post, we&amp;rsquo;ll explore the fundamentals of getting started with Rust.&lt;/p&gt;
&lt;h3 id="installation"&gt;Installation&lt;/h3&gt;
&lt;p&gt;The easiest way to install Rust is using rustup:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl --proto &lt;span class="s1"&gt;&amp;#39;=https&amp;#39;&lt;/span&gt; --tlsv1.2 -sSf https://sh.rustup.rs &lt;span class="p"&gt;|&lt;/span&gt; sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="your-first-program"&gt;Your First Program&lt;/h3&gt;
&lt;p&gt;Create a new project with Cargo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cargo new hello_world
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; hello_world
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Edit &lt;code&gt;src/main.rs&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello, world!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run your program:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cargo run
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="key-concepts"&gt;Key Concepts&lt;/h3&gt;
&lt;h4 id="ownership"&gt;Ownership&lt;/h4&gt;
&lt;p&gt;Rust&amp;rsquo;s most distinctive feature is its ownership system. Every value in Rust has a single owner, and when the owner is dropped, the value is freed.&lt;/p&gt;
&lt;h4 id="borrowing"&gt;Borrowing&lt;/h4&gt;
&lt;p&gt;Instead of moving ownership, you can borrow values:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;: &lt;span class="kp"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt; &lt;span class="kt"&gt;usize&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="pattern-matching"&gt;Pattern Matching&lt;/h4&gt;
&lt;p&gt;Rust&amp;rsquo;s &lt;code&gt;match&lt;/code&gt; expression is incredibly powerful:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;One to five&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Greater than five&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="next-steps"&gt;Next Steps&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Read &lt;a href="https://doc.rust-lang.org/book/"&gt;The Rust Book&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Practice on &lt;a href="https://exercism.org/"&gt;Exercism&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Join the &lt;a href="https://www.rust-lang.org/community"&gt;Rust Community&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;</description></item><item><title>JavaScript is (too) liberal</title><link>https://luizmartins.dev/post/javascript-is-too-liberal/</link><pubDate>Sat, 26 Jul 2025 00:00:00 +0000</pubDate><author>Luiz Carlos Martins Filho</author><guid>https://luizmartins.dev/post/javascript-is-too-liberal/</guid><description>&lt;p&gt;&lt;img src="featured.jpg" alt="Featured Image"&gt;&lt;/p&gt;
&lt;p&gt;JavaScript é uma linguagem notavelmente permissiva, o que pode ser tanto uma bênção quanto uma maldição para desenvolvedores. Esta publicação explora os aspectos liberais da linguagem e suas implicações para a qualidade do código e experiência do desenvolvedor.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mais conteúdo em breve&amp;hellip;&lt;/p&gt;&lt;/blockquote&gt;</description></item><item><title>Repositório de ideias</title><link>https://luizmartins.dev/post/repositorio-de-ideias/</link><pubDate>Sat, 12 Jul 2025 00:00:00 +0000</pubDate><author>Luiz Carlos Martins Filho</author><guid>https://luizmartins.dev/post/repositorio-de-ideias/</guid><description>&lt;p&gt;Este blog funciona como um repositório de tudo quanto estou lendo, pensando ou que me interessa. É um retorno à tradição dos blogs pessoais da era anterior às redes sociais, onde cada pessoa mantinha seu próprio espaço na internet.&lt;/p&gt;
&lt;h2 id="o-propósito"&gt;O propósito&lt;/h2&gt;
&lt;p&gt;Em um mundo dominado por algoritmos e feeds infinitos, há algo especial em manter um espaço genuinamente pessoal. Um lugar onde ideias podem ser exploradas livremente, sem preocupação com engagement ou alcance. Apenas pensamentos, leituras e reflexões.&lt;/p&gt;
&lt;p&gt;Bem-vindo ao Blog do Luiz!&lt;/p&gt;</description></item><item><title>Coming soon</title><link>https://luizmartins.dev/post/coming-soon/</link><pubDate>Fri, 11 Jul 2025 00:00:00 +0000</pubDate><author>Luiz Carlos Martins Filho</author><guid>https://luizmartins.dev/post/coming-soon/</guid><description>&lt;p&gt;Bem-vindo ao Blog do Luiz!&lt;/p&gt;
&lt;p&gt;Este é o primeiro post do blog, que ainda está em desenvolvimento. Coisas estarão em funcionamento muito em breve, mas você pode se inscrever no meio do caminho se quiser ficar atualizado e receber emails quando novo conteúdo for publicado!&lt;/p&gt;
&lt;p&gt;Obrigado pelo interesse! 🙌&lt;/p&gt;</description></item></channel></rss>