<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Articles and programming tutorials on Cesar Gimenes</title><link>https://crg.eti.br/pub/</link><description>Recent content in Articles and programming tutorials on Cesar Gimenes</description><generator>Hugo -- gohugo.io</generator><language>en</language><managingEditor>crg@crg.eti.br (Cesar Gimenes)</managingEditor><webMaster>crg@crg.eti.br (Cesar Gimenes)</webMaster><lastBuildDate>Thu, 20 Jun 2019 01:30:36 -0200</lastBuildDate><atom:link href="https://crg.eti.br/pub/index.xml" rel="self" type="application/rss+xml"/><item><title>Kutta in the Browser: Same Code, a Different Frame Budget</title><link>https://crg.eti.br/pub/kutta-no-navegador/</link><pubDate>Sun, 16 Aug 2026 10:30:00 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/kutta-no-navegador/</guid><description>&lt;p>&lt;a href="https://crg.eti.br/en/pub/kutta/">Kutta&lt;/a> now runs inside a browser tab. Same source as the desktop build, &lt;code>GOOS=js GOARCH=wasm&lt;/code>, no fork, no duplicated file holding a &amp;ldquo;web&amp;rdquo; version of the solver.&lt;/p>
&lt;figure class="media-frame media-center fade-in media-gif">
&lt;a href="https://crgimenes.itch.io/kutta">&lt;img alt="Kutta shedding vortices at 20 degrees angle of attack" src="https://crg.eti.br/pub/kutta-no-navegador/vortices.webp" height="560" width="800" loading="lazy" decoding="async">&lt;/a>
&lt;/figure>
&lt;p>Speed is what you pay. A solver step costs &lt;strong>6.1 ms under wasm against 2.3 ms native&lt;/strong>, measured on the 360x200 grid the app runs, on an M4 Mac, same solver compiled for both targets on the same machine. Factor of 2.6.&lt;/p></description></item><item><title>Kutta, a Tiny Wind Tunnel in Go</title><link>https://crg.eti.br/pub/kutta/</link><pubDate>Wed, 08 Jul 2026 00:30:00 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/kutta/</guid><description>&lt;p>You can explain lift with a diagram and an equation. It rarely sticks. Watch a wake peel off the back of a wing while you turn the angle of attack, and it sticks immediately. That gap is the whole reason &lt;strong>Kutta&lt;/strong> exists.&lt;/p>
&lt;p>It is a small 2D wind tunnel written in Go, rendered with &lt;a href="https://ebitengine.org">Ebitengine&lt;/a>, running as a single desktop app.&lt;/p>
&lt;figure class="media-frame media-center fade-in media-gif">
&lt;a href="https://github.com/crgimenes/kutta">&lt;img alt="Kutta running" src="https://crg.eti.br/pub/kutta/kutta.webp" height="338" width="600" loading="lazy" decoding="async">&lt;/a>
&lt;/figure>
&lt;p>The idea never grew past the first sketch: stream air past an airfoil and make the flow visible. Change the angle of attack and the field reacts. Toggle between speed, vorticity and a pressure-like field. Draw your own shape. Cut a wing into a wing and a flap, animate the flap, and watch the wake go unstable when the geometry or the angle gets greedy.&lt;/p></description></item><item><title>Glaze, a Desktop WebView in Go Without CGO</title><link>https://crg.eti.br/pub/glaze/</link><pubDate>Mon, 22 Jun 2026 10:15:00 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/glaze/</guid><description>&lt;p>Opening a window with HTML in Go almost always charges a toll in C.&lt;/p>
&lt;p>Either you turn on cgo and drag a C toolchain into the project, or someone embeds a compiled &lt;code>.dll&lt;/code>/&lt;code>.so&lt;/code>/&lt;code>.dylib&lt;/code> in the binary and extracts it to disk on first run. Both work. And both take away exactly what I like about the ecosystem: the &lt;code>go build&lt;/code> that cross-compiles to three systems without a second thought, the reproducible build, the &lt;code>go install&lt;/code> that works for anyone who cloned the repo. It&amp;rsquo;s the first thing that goes the moment C enters the picture.&lt;/p></description></item><item><title>singleflight in Go</title><link>https://crg.eti.br/pub/singleflight/</link><pubDate>Sat, 13 Jun 2026 09:57:41 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/singleflight/</guid><description>&lt;p>You have an expensive, heavy function. During a traffic spike, six requests arrive at the same time asking for exactly the same thing. With no precautions, you run that function six times to get six identical results.&lt;/p>
&lt;p>&lt;strong>singleflight&lt;/strong> is a pattern that collapses those calls. The first call for a key does the real work. Every other call that arrives &lt;em>while it&amp;rsquo;s in progress&lt;/em> waits and gets the same result. One execution, many consumers.&lt;/p></description></item><item><title>Overlapping text chunker for RAG pipelines</title><link>https://crg.eti.br/pub/text_chunker/</link><pubDate>Sat, 06 Jun 2026 11:57:59 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/text_chunker/</guid><description>&lt;p>In a RAG (&lt;em>Retrieval-Augmented Generation&lt;/em>) pipeline the first step is almost always the same: take a large text and break it into pieces before vectorizing. The pieces can&amp;rsquo;t be too big, because the model has a context limit, nor too small, because then the embedding loses semantics. And neighbors need to overlap, otherwise an answer that lands right on the boundary gets squeezed between two chunks and the retriever misses.&lt;/p></description></item><item><title>An encrypted vault in Go</title><link>https://crg.eti.br/pub/cofre-cifrado-em-go/</link><pubDate>Sun, 31 May 2026 01:02:01 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/cofre-cifrado-em-go/</guid><description>&lt;p>Let&amp;rsquo;s put together the three previous pieces:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://crg.eti.br/pub/capturando-senhas-no-terminal-go/">terminal password input&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://crg.eti.br/pub/criptografia-at-rest-com-a-stdlib-go/">encryption at rest&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://crg.eti.br/pub/sqlite-na-ram-serialize-deserialize/">SQLite snapshot&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>A SQLite database that lives in RAM and, on disk, exists only as an encrypted blob.&lt;/p>
&lt;p>The database runs in &lt;code>:memory:&lt;/code>.
On exit, we take a &lt;em>snapshot&lt;/em> of the database bytes, encrypt it with the password, and write it out.
On startup, we read the blob, decrypt it with the password, and &lt;em>deserialize&lt;/em> it back into RAM.&lt;/p></description></item><item><title>SQLite in RAM: serialize and deserialize in Go</title><link>https://crg.eti.br/pub/sqlite-na-ram-serialize-deserialize/</link><pubDate>Sun, 31 May 2026 00:46:31 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/sqlite-na-ram-serialize-deserialize/</guid><description>&lt;p>SQLite can run entirely in memory, without ever touching disk. And there is a little-known trick: you can take a &lt;em>snapshot&lt;/em> of the database bytes and load them back later, with no &lt;code>INSERT&lt;/code>, no rebuilding anything. The functions are &lt;code>sqlite3_serialize&lt;/code> and &lt;code>sqlite3_deserialize&lt;/code>.&lt;/p>
&lt;p>I will use the &lt;code>modernc.org/sqlite&lt;/code> driver, which is pure Go, no CGo.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">db&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">sql&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Open&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;sqlite&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;:memory:&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">fatal&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">db&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">SetMaxOpenConns&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The catch is in &lt;code>SetMaxOpenConns(1)&lt;/code>. A &lt;code>:memory:&lt;/code> database belongs to the connection that opened it. Without limiting it to one connection, the &lt;code>database/sql&lt;/code> pool could open another one, and that one would see a different, empty database.&lt;/p></description></item><item><title>Encryption at rest with Go's stdlib</title><link>https://crg.eti.br/pub/criptografia-at-rest-com-a-stdlib-go/</link><pubDate>Sun, 31 May 2026 00:38:32 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/criptografia-at-rest-com-a-stdlib-go/</guid><description>&lt;p>I want to store a piece of data on disk so that, even if the file leaks, it is only readable with the password and any tampering is detected.&lt;/p>
&lt;p>To do this we protect the data by encrypting it &amp;ldquo;at rest&amp;rdquo;, which basically means the data is protected while it sits on disk and can only be accessed by whoever has the right password.&lt;/p>
&lt;p>You can do this with the standard library alone:&lt;/p></description></item><item><title>Capturing Passwords in the Terminal with Go</title><link>https://crg.eti.br/pub/capturando-senhas-no-terminal-go/</link><pubDate>Sat, 30 May 2026 10:00:00 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/capturando-senhas-no-terminal-go/</guid><description>&lt;p>Reading a password in the terminal looks trivial, but it has two pitfalls: the password shows up on screen if you use ordinary input, and you need to make sure you&amp;rsquo;re really dealing with a terminal and not a redirection. Let&amp;rsquo;s solve both with the &lt;code>golang.org/x/term&lt;/code> package.&lt;/p>
&lt;p>If you read with &lt;code>bufio.Scanner&lt;/code> or &lt;code>fmt.Scanln&lt;/code>, every keystroke shows up on screen. That won&amp;rsquo;t do for a password. &lt;code>term.ReadPassword&lt;/code> reads straight from the terminal, without echo:&lt;/p></description></item><item><title>Neko, a cat chasing the mouse with Go and Ebitengine</title><link>https://crg.eti.br/pub/neko/</link><pubDate>Sat, 11 Apr 2026 09:15:00 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/neko/</guid><description>&lt;p>Every programmer should write at least one useless piece of software on purpose.&lt;/p>
&lt;p>Useless here in the best sense. It serves no business, will never show up in a product meeting, and stands no chance of some manager asking for webhook integration. Even so, it forces you to deal with real problems. Screen, input, timing, sprites, sound, window, operating system. A toy like that teaches more about interactive software than a pile of CRUD apps dressed up as corporate demos.&lt;/p></description></item><item><title>Triggers in SQLite</title><link>https://crg.eti.br/pub/trigger-no-sqlite/</link><pubDate>Fri, 03 Oct 2025 23:57:24 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/trigger-no-sqlite/</guid><description>&lt;p>&lt;em>SQLite&lt;/em> does not support &lt;em>stored procedures&lt;/em> directly, but it does support &lt;em>triggers&lt;/em>, which is a very useful feature for automating certain actions.&lt;/p>
&lt;p>For example, automatically updating the &lt;code>updated_at&lt;/code> field.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">CREATE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">TABLE&lt;/span>&lt;span style="color:#fff"> &lt;/span>users&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>id&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">INTEGER&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">PRIMARY&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">KEY&lt;/span>&lt;span style="color:#fff"> &lt;/span>AUTOINCREMENT&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>nome&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">TEXT&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>updated_at&lt;span style="color:#fff"> &lt;/span>DATETIME&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">DEFAULT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">CURRENT_TIMESTAMP&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">CREATE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">TRIGGER&lt;/span>&lt;span style="color:#fff"> &lt;/span>update_timestamp&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">BEFORE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">UPDATE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">ON&lt;/span>&lt;span style="color:#fff"> &lt;/span>users&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">FOR&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">EACH&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">ROW&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">BEGIN&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">UPDATE&lt;/span>&lt;span style="color:#fff"> &lt;/span>users&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">SET&lt;/span>&lt;span style="color:#fff"> &lt;/span>updated_at&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">CURRENT_TIMESTAMP&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">WHERE&lt;/span>&lt;span style="color:#fff"> &lt;/span>id&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">OLD&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>id&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">END&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, whenever you update a record in the &lt;code>users&lt;/code> table, the &lt;code>updated_at&lt;/code> field will be automatically set to the current &lt;em>timestamp&lt;/em>.&lt;/p></description></item><item><title>Recursive Go function to access values in nested maps</title><link>https://crg.eti.br/pub/get-from-map/</link><pubDate>Mon, 22 Sep 2025 17:33:43 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/get-from-map/</guid><description>&lt;p>Recently, I received a response from an API that contained a JSON with a complex, large, and nested structure. I needed to access a specific value inside that structure, but the path to that value could vary.&lt;/p>
&lt;p>The idea was to create a recursive function that takes a list with the path to the desired value and the data structure (a nested map) and returns the corresponding value, if found.&lt;/p></description></item><item><title>Starting services with /etc/rc.local like in the 80s</title><link>https://crg.eti.br/pub/etc-rc-local/</link><pubDate>Sun, 20 Jul 2025 14:19:38 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/etc-rc-local/</guid><description>&lt;p>I often use the &lt;code>/etc/rc.local&lt;/code> &lt;em>script&lt;/em> to quickly start services during boot. It is convenient, simple, and works well on Debian and other Linux distributions. It is essentially just an sh script (or whichever shell you prefer) that runs during boot.&lt;/p>
&lt;p>Interestingly, &lt;em>rc.local&lt;/em> has been considered obsolete since the release of &lt;em>UNIX System III&lt;/em> in 1983!&lt;/p>
&lt;p>Since then, several attempts have been made to retire this file. It has not been recommended for a long time in favor of more modern solutions for starting services during boot, but it still persists. If the &lt;code>/etc/rc.local&lt;/code> file does not exist on your system, try creating it and giving it execute permission. There is a good chance systemd will recognize that you are fully &lt;em>old school&lt;/em> and run &lt;em>rc.local&lt;/em> normally during &lt;em>boot&lt;/em>, even politely waiting for the network to come up before running it (tested on Debian and Ubuntu).&lt;/p></description></item><item><title>sftpdav: Remote Access via SSH with WebDAV</title><link>https://crg.eti.br/pub/serve-webdav-with-go/</link><pubDate>Sat, 15 Mar 2025 18:11:26 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/serve-webdav-with-go/</guid><description>&lt;p>Recently, I faced a challenge when trying to access files on a machine that only allows SSH connections. Opening additional ports or installing third-party extensions wasn’t feasible due to security and compatibility issues, especially on macOS.&lt;/p>
&lt;p>That’s how the idea for &lt;strong>sftpdav&lt;/strong> came about: a program that combines an SFTP client with a WebDAV server, allowing you to access a remote directory via SSH and mount it locally as a WebDAV share.&lt;/p></description></item><item><title>Protecting Credentials and Configurations with an Encrypted Container.</title><link>https://crg.eti.br/pub/protegendo-credenciais-e-configuracoes-com-conteiner-criptografado/</link><pubDate>Thu, 20 Feb 2025 22:43:56 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/protegendo-credenciais-e-configuracoes-com-conteiner-criptografado/</guid><description>&lt;p>I use a small pocket computer in my backpack. This device is used for testing and development, and it stores sensitive information such as credentials, passwords, and access keys. I don’t want this data to fall into the wrong hands. Unlike my laptop, which has an encrypted drive, my pocket computer’s drive isn’t encrypted. Drive-wide encryption consumes a lot of processing power and usually requires disabling SSD TRIM, which hurts performance.&lt;/p></description></item><item><title>LQS: A Practical Tool for Testing and Debugging SQL</title><link>https://crg.eti.br/pub/lqs-uma-ferramenta-prtica-para-testar-sql/</link><pubDate>Sat, 15 Feb 2025 18:31:26 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/lqs-uma-ferramenta-prtica-para-testar-sql/</guid><description>&lt;p>It&amp;rsquo;s very common to need to embed SQL code strings in the source of other languages. The problem is that SQL is an interpreted language, so it can contain errors that we only notice at runtime.&lt;/p>
&lt;h2 id="testing-sql">Testing SQL&lt;/h2>
&lt;p>LQS was created to work together with Neovim and allow you to test SQL while editing, without having to copy and paste into another file or SQL client.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Test SQL with embedded metadata:&lt;/strong>
Insert configurations directly in your SQL script, such as the connection string, JSON output option, or even an extra query to generate parameters.
Example:&lt;/p></description></item><item><title>Sorting and Removing Duplicate Lines with Neovim</title><link>https://crg.eti.br/pub/nvim-sort/</link><pubDate>Sun, 09 Feb 2025 14:32:33 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/nvim-sort/</guid><description>&lt;p>Good organization makes code easier to read. Disorganized lists make it difficult to maintain a project, and they also give your code an unprofessional look.&lt;/p>
&lt;p>These two functions sort and remove duplicate lines in selected text blocks in &lt;em>Neovim&lt;/em>.&lt;/p>
&lt;p>The &lt;code>sort_lines&lt;/code> function sorts the selected lines:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-lua" data-lang="lua">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">sort_lines&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> start_pos &lt;span style="color:#0550ae">=&lt;/span> vim.fn&lt;span style="color:#1f2328">.&lt;/span>getpos&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&amp;#39;&amp;lt;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> end_pos &lt;span style="color:#0550ae">=&lt;/span> vim.fn&lt;span style="color:#1f2328">.&lt;/span>getpos&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&amp;#39;&amp;gt;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> start_line &lt;span style="color:#0550ae">=&lt;/span> start_pos&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">-&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> end_line &lt;span style="color:#0550ae">=&lt;/span> end_pos&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> lines &lt;span style="color:#0550ae">=&lt;/span> vim.api&lt;span style="color:#1f2328">.&lt;/span>nvim_buf_get_lines&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> start_line&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> end_line&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">false&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> table.sort&lt;span style="color:#1f2328">(&lt;/span>lines&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> vim.api&lt;span style="color:#1f2328">.&lt;/span>nvim_buf_set_lines&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> start_line&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> end_line&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> lines
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The &lt;code>sort_and_uniq_lines&lt;/code> function sorts and removes duplicate lines:&lt;/p></description></item><item><title>Bookmarks in Neovim</title><link>https://crg.eti.br/pub/nvim-bookmarks/</link><pubDate>Sun, 09 Feb 2025 11:52:14 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/nvim-bookmarks/</guid><description>&lt;p>I go through many files when I work, especially when debugging or tracing behaviors. I created a bookmark system in &lt;em>Neovim&lt;/em> to quickly jump between files. This system differs from the default &lt;em>Neovim&lt;/em> system because it focuses on marking files and lines, not just positions within the same file.&lt;/p>
&lt;h2 id="how-it-works">How It Works&lt;/h2>
&lt;p>The system records the file path and the current line in a text file. I use the &lt;code>&amp;lt;leader&amp;gt;o&lt;/code> key to open all marked files. I use the &lt;code>&amp;lt;leader&amp;gt;m&lt;/code> key to mark a file. I also use the &lt;code>:Clearmarks&lt;/code> command to clear all bookmarks when I finish a task or start a new one.&lt;/p></description></item><item><title>GoScope: Exploring and Navigating Go Projects</title><link>https://crg.eti.br/pub/goscope-explorando-e-navegando-em-projetos-go/</link><pubDate>Sun, 09 Feb 2025 02:47:39 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/goscope-explorando-e-navegando-em-projetos-go/</guid><description>&lt;p>I often want to quickly analyze a Go project to understand where functions, variables, and types are defined or called. That&amp;rsquo;s why I created two command-line tools: &lt;strong>GoScope&lt;/strong> and &lt;strong>rgs&lt;/strong>. The first scans every &lt;code>.go&lt;/code> file in a project, producing a list of definitions and function calls. The second uses that list to let me navigate interactively to the exact spot in the code.&lt;/p>
&lt;h2 id="goscope">GoScope&lt;/h2>
&lt;p>&lt;a href="https://github.com/crgimenes/GoScope">&lt;strong>GoScope&lt;/strong>&lt;/a> walks through all &lt;code>.go&lt;/code> files recursively starting from the current directory. It prints:&lt;/p></description></item><item><title>Running Remote Commands Interactively with SSH</title><link>https://crg.eti.br/pub/executando-comandos-remotos-de-forma-interativa-com-ssh/</link><pubDate>Sat, 08 Feb 2025 13:38:17 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/executando-comandos-remotos-de-forma-interativa-com-ssh/</guid><description>&lt;p>I often need to run a command on a remote server without starting a full interactive session. I want the program to keep all the characteristics of a local process while running on the remote server.&lt;/p>
&lt;p>At first, I just used the &lt;code>ssh&lt;/code> command, specifying the server and the command to run:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>ssh server &lt;span style="color:#6639ba">command&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This method doesn&amp;rsquo;t work well for programs that require a pseudo terminal, like &lt;em>Neovim&lt;/em>. To fix that, I tried the &lt;code>-t&lt;/code> option to force pseudo terminal allocation. With it, programs like &lt;code>ls&lt;/code> display colors, but the user environment isn&amp;rsquo;t loaded. In that case, I need to pass the &lt;code>--color&lt;/code> option to &lt;code>ls&lt;/code>. Even so, programs like &lt;em>Neovim&lt;/em> fail because the &lt;em>shell&lt;/em> doesn&amp;rsquo;t behave as interactive and ANSI codes aren&amp;rsquo;t processed correctly.&lt;/p></description></item><item><title>Traceback in Go: How to Explore the Call Stack</title><link>https://crg.eti.br/pub/tracebacks-em-go/</link><pubDate>Thu, 06 Feb 2025 02:12:46 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/tracebacks-em-go/</guid><description>&lt;p>Many programming languages provide some kind of &amp;ldquo;stack trace&amp;rdquo; or &amp;ldquo;backtrace&amp;rdquo;. Python has the &lt;code>traceback&lt;/code> module, C on Linux offers the &lt;code>backtrace()&lt;/code> function in &lt;code>execinfo.h&lt;/code> (not part of the C standard), and Java includes &lt;code>Thread.dumpStack()&lt;/code> or &lt;code>e.printStackTrace()&lt;/code> for exceptions.&lt;/p>
&lt;h2 id="stack-trace-in-go">Stack Trace in Go&lt;/h2>
&lt;p>Go provides the &lt;code>runtime.Caller&lt;/code> function to get information about the call stack. The following example prints the file, line, and function that called &lt;code>info()&lt;/code>. Note that the argument &lt;code>1&lt;/code> passed to &lt;code>runtime.Caller&lt;/code> means we want information about the function that called &lt;code>info()&lt;/code>:&lt;/p></description></item><item><title>Data Transmission Using Sound: An Experiment with a 'Cup Telephone'</title><link>https://crg.eti.br/pub/transmissao-de-dados-usando-som-via-telefone-de-copos/</link><pubDate>Sat, 25 Jan 2025 21:58:10 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/transmissao-de-dados-usando-som-via-telefone-de-copos/</guid><description>&lt;p>When I started playing with computers, the only way to load a program into the machine was to type it from scratch. My old computer had no storage; there was no hard drive, floppy disk, or any other way to store data. At startup, the machine loaded &lt;em>BASIC&lt;/em> straight from ROM and that was it. Eventually I got a tape recorder, but it was terrible. With no money for a recorder made for computers, I used a household one. It took a long time adjusting the volume and other settings before I could load anything. The equipment was so finicky that I taped the controls down to keep them from moving, because the slightest change would prevent loading.&lt;/p></description></item><item><title>Static Compilation of the Lua Interpreter: Consistency and Portability</title><link>https://crg.eti.br/pub/compilacao-estatica-da-lingagem-lua/</link><pubDate>Sun, 19 Jan 2025 11:21:08 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/compilacao-estatica-da-lingagem-lua/</guid><description>&lt;p>Lua is my favorite language for writing small scripts and configurations. It is easy to embed in other projects and has a clean, simple syntax. It is easy to extend and a great language for configuring systems.&lt;/p>
&lt;p>I recently started a project that requires the Lua interpreter to be installed. That is usually not a problem. But to have full control, I decided to compile my own statically linked version of the interpreter. This ensures that differences in the libc version or other libraries won&amp;rsquo;t interfere with my system. I&amp;rsquo;ve run into plenty of problems with systems that failed to load because of mismatched glibc versions. Beyond the practical reasons, I believe all software should be statically compiled. The memory savings and easier updates of dynamic linking don&amp;rsquo;t make up for the problems it can cause.&lt;/p></description></item><item><title>Finding Program Paths on the System with exec.LookPath in Go</title><link>https://crg.eti.br/pub/encontrando-os-paths-de-executaveis-usando-go/</link><pubDate>Sat, 18 Jan 2025 22:58:48 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/encontrando-os-paths-de-executaveis-usando-go/</guid><description>&lt;p>I started a new project that needs to check whether certain programs are installed on the system and get their full paths. For that, I used the &lt;code>exec.LookPath&lt;/code> function from the &lt;code>os/exec&lt;/code> package.&lt;/p>
&lt;p>The &lt;code>exec.LookPath&lt;/code> function searches for an executable in the directories listed in the &lt;code>PATH&lt;/code> environment variable. If it doesn&amp;rsquo;t find one, it returns an error. So I created the &lt;code>programPath&lt;/code> function, which takes the program name and returns the executable&amp;rsquo;s path and a boolean indicating whether the program was found.&lt;/p></description></item><item><title>Optimizing Message Integrity Checks with FNV-1a in Go</title><link>https://crg.eti.br/pub/checksum-com-golang/</link><pubDate>Sat, 18 Jan 2025 00:43:18 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/checksum-com-golang/</guid><description>&lt;p>In the article &lt;a href="https://crg.eti.br/pub/hmac-assinatura-de-mensagens-segura-em-go/">HMAC (Hash-based Message Authentication Code)&lt;/a>, we saw how that technique ensures a message was not altered in transit and confirms the validity of the signature.&lt;/p>
&lt;p>However, while secure, that process is slow and resource-intensive. When we only need to verify message integrity without validating a signature, we can use a faster hash function. For that, we will use the FNV-1a (Fowler-Noll-Vo) algorithm, known for its speed and low collision rate.&lt;/p></description></item><item><title>mTLS: Implementing Mutual Authentication Between Client and Server in Go</title><link>https://crg.eti.br/pub/mtls-implementando-autenticacao-mutua/</link><pubDate>Sat, 11 Jan 2025 19:49:40 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/mtls-implementando-autenticacao-mutua/</guid><description>&lt;p>mTLS (Mutual TLS) authenticates both client and server. Each one presents a digital certificate signed by a trusted certificate authority. By controlling certificate issuance, you ensure that only authorized clients access your service. It also makes it easy to identify the client without needing an API Key or Token. I also recommend using an &lt;a href="https://crg.eti.br/pt-br/pub/hmac-assinatura-de-mensagens-segura-em-go/">HMAC (Hash-based Message Authentication Code)&lt;/a> header as an additional layer of security and message integrity.&lt;/p>
&lt;h2 id="creating-certificates">Creating Certificates&lt;/h2>
&lt;p>In this example, I&amp;rsquo;ll create the certificates in a simple way for local testing. When deploying to production, be careful with the parameters you use. It&amp;rsquo;s important to include Subject Alternative Names (SANs), since relying on the CN (Common Name) alone is no longer recommended.&lt;/p></description></item><item><title>HMAC (Hash-based Message Authentication Code) in Golang</title><link>https://crg.eti.br/pub/hmac-assinatura-de-mensagens-segura-em-go/</link><pubDate>Fri, 10 Jan 2025 23:33:11 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/hmac-assinatura-de-mensagens-segura-em-go/</guid><description>&lt;p>When building APIs, it&amp;rsquo;s a good idea to add an authentication header to guarantee message integrity. For example, when your server sends a request or a webhook, include an &lt;code>X-Signature&lt;/code> header with an HMAC (Hash-based Message Authentication Code) signature.&lt;/p>
&lt;p>To generate the HMAC signature, you use a secret key and the content to be signed, such as the request &lt;em>body&lt;/em>, and send the signature in the header. It&amp;rsquo;s important to make clear exactly what is being signed. I&amp;rsquo;ve run into problems with clients who couldn&amp;rsquo;t validate the signature because they used the &lt;em>body&lt;/em> parsed as JSON instead of the &lt;em>raw body&lt;/em> received in the request.&lt;/p></description></item><item><title>Safe JSON Validation and Integration in Go APIs with json.RawMessage</title><link>https://crg.eti.br/pub/validacao-e-integracao-segura-de-json-em-apis-go/</link><pubDate>Thu, 09 Jan 2025 00:28:29 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/validacao-e-integracao-segura-de-json-em-apis-go/</guid><description>&lt;p>I recently built an API where the user sends a JSON value in one of the fields. The requirement was to log invalid JSON errors but let the rest of the data continue through the system&amp;rsquo;s normal flow.&lt;/p>
&lt;p>It was also important that, if the received JSON was valid, it would be integrated seamlessly into the API responses. Since the JSON could vary and I didn&amp;rsquo;t know its structure, I used &lt;code>json.RawMessage&lt;/code> as the field type. That way, when calling &lt;code>json.Marshal&lt;/code>, the data is correctly embedded into the main JSON.&lt;/p></description></item><item><title>Fork Bomb: From Code to Defense</title><link>https://crg.eti.br/pub/forkbomb-do-codigo-a-defesa/</link><pubDate>Sat, 04 Jan 2025 11:48:47 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/forkbomb-do-codigo-a-defesa/</guid><description>&lt;p>The first time I heard about fork bombs was a long time ago. Although I found it fascinating that a piece of code could spawn two more processes of itself, causing exponential process growth and eventually freezing the system, I didn&amp;rsquo;t believe it was a viable attack until I discovered how many systems are vulnerable to code injection.&lt;/p>
&lt;h2 id="what-is-a-fork-bomb">What is a fork bomb?&lt;/h2>
&lt;p>In general terms, a fork bomb is code that spawns processes recursively. The first process spawns copies of itself, those copies spawn more copies, and so on, until the system runs out of resources and freezes. The result is a DoS (Denial of Service) attack.&lt;/p></description></item><item><title>Manipulating Special Permission Bits</title><link>https://crg.eti.br/pub/manipulando-setuid-e-setgid/</link><pubDate>Sat, 04 Jan 2025 00:36:51 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/manipulando-setuid-e-setgid/</guid><description>&lt;p>In the article on &lt;a href="https://crg.eti.br/pub/reducao-de-privilegios-com-golang/">Privilege Reduction in Programs&lt;/a>, we used the &lt;code>sudo&lt;/code> command to run a program with superuser privileges. However, it&amp;rsquo;s possible to do this without an external command.&lt;/p>
&lt;p>For that, we use special file permissions known as the &lt;em>setuid bit&lt;/em> and the &lt;em>setgid bit&lt;/em>. These attributes allow files to be executed with the &lt;strong>privileges of the owning user or group&lt;/strong>.&lt;/p>
&lt;p>To set the &lt;code>setuid&lt;/code> and &lt;code>setgid&lt;/code> bits, we use the &lt;code>chmod&lt;/code> command with the &lt;code>u+s&lt;/code> and &lt;code>g+s&lt;/code> options, respectively.&lt;/p></description></item><item><title>Dropping Privileges in Go Programs to Improve Security</title><link>https://crg.eti.br/pub/reducao-de-privilegios-com-golang/</link><pubDate>Thu, 02 Jan 2025 22:43:45 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/reducao-de-privilegios-com-golang/</guid><description>&lt;p>A good practice for improving the security of a system is to drop a program&amp;rsquo;s execution privileges. Ideally, a program should run with the fewest privileges possible.&lt;/p>
&lt;p>On UNIX-like systems, you can change the user and group a program runs as. Let&amp;rsquo;s walk through how to do that in Go.&lt;/p>
&lt;h2 id="checking-whether-the-program-is-running-as-root">Checking Whether the Program Is Running as Root&lt;/h2>
&lt;p>First, check whether the program is running as root. This matters because we&amp;rsquo;ll use system calls that require root privileges. (There are other ways to grant these privileges, but we&amp;rsquo;ll cover that in another article.)&lt;/p></description></item><item><title>References in Comments with Golang</title><link>https://crg.eti.br/pub/referencias-nos-comentarios-com-golang/</link><pubDate>Wed, 01 Jan 2025 13:28:17 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/referencias-nos-comentarios-com-golang/</guid><description>&lt;p>A quick tip about comments in Go: include references in them. Put the element you want to reference between brackets (&lt;strong>[&lt;/strong> and &lt;strong>]&lt;/strong>). It works with anything that can be referenced, such as variables, constants, functions, and so on.&lt;/p>
&lt;p>Here is an example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">package&lt;/span> &lt;span style="color:#1f2328">main&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;fmt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;time&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">// pi representa a constante matemática Pi&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">pi&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#0550ae">3.14159&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">// CalcularArea calcula a área de um círculo dado o raio.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">// Utiliza a constante [pi] para o cálculo.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#6639ba">CalcularArea&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">raio&lt;/span> &lt;span style="color:#cf222e">float64&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">float64&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">pi&lt;/span> &lt;span style="color:#0550ae">*&lt;/span> &lt;span style="color:#1f2328">raio&lt;/span> &lt;span style="color:#0550ae">*&lt;/span> &lt;span style="color:#1f2328">raio&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#6639ba">main&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">raio&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#0550ae">5.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">area&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#6639ba">CalcularArea&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">raio&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">fmt&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Printf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;A área do círculo com raio %.2f é %.2f\n&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">raio&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">area&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> Formatos úteis:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> [time.DateTime]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> [time.Kitchen]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> [time.RFC3339Nano]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> [time.RFC3339]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">fmt&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">time&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Now&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#6639ba">Format&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">time&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">DateTime&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In Neovim, place the cursor between the brackets and press &lt;code>Ctrl-]&lt;/code> to jump to the definition of the referenced element. To go back, press &lt;code>Ctrl-t&lt;/code>. In VSCode, use the &lt;code>Go to Definition&lt;/code> extension to do the same thing.&lt;/p></description></item><item><title>Plasma Effect in the Terminal with Golang</title><link>https://crg.eti.br/pub/efeito-plasma-no-terminal-com-golang/</link><pubDate>Tue, 31 Dec 2024 17:34:13 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/efeito-plasma-no-terminal-com-golang/</guid><description>&lt;p>One kind of program I&amp;rsquo;ve always found interesting is the &lt;em>demo&lt;/em>: eye-catching graphical effects with code that squeezes every ounce of performance out of the machine. The plasma effect is one of my favorites, simulating a fluid in motion.&lt;/p>
&lt;figure class="media-frame media-center fade-in">&lt;a href="https://crg.eti.br/pub/efeito-plasma-no-terminal-com-golang/plasma.webp">
&lt;picture>
&lt;source media="(max-width: 480px)" srcset="https://crg.eti.br/pub/efeito-plasma-no-terminal-com-golang/plasma_hu_3e89f9757017ba57.webp">
&lt;source media="(max-width: 1080px)" srcset="https://crg.eti.br/pub/efeito-plasma-no-terminal-com-golang/plasma_hu_3490c725fbb4fdb0.webp">
&lt;img alt="plasma in the terminal with Go" src="https://crg.eti.br/pub/efeito-plasma-no-terminal-com-golang/plasma_hu_5639f6b4b1ba2b78.webp" height="832" width="1280" loading="lazy" decoding="async">
&lt;/picture>
&lt;/a>&lt;/figure>&lt;p>To create the plasma effect, I use several trigonometric functions to calculate the background color of each character, passing time as a parameter to generate the animation. The code is relatively simple, but the optimization is a bit more complex.&lt;/p></description></item><item><title>Happy 2025, Fireworks in the Terminal with Golang</title><link>https://crg.eti.br/pub/feliz-2025-com-fogos-de-artificio-no-terminal-com-golang/</link><pubDate>Tue, 31 Dec 2024 13:09:42 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/feliz-2025-com-fogos-de-artificio-no-terminal-com-golang/</guid><description>&lt;p>A small program celebrates the arrival of 2025 with fireworks in the terminal. It includes several interesting tricks to start your year with plenty of code.&lt;/p>
&lt;figure class="media-frame media-center fade-in">&lt;a href="https://crg.eti.br/pub/feliz-2025-com-fogos-de-artificio-no-terminal-com-golang/fireworks-em-golang.webp">
&lt;picture>
&lt;source media="(max-width: 480px)" srcset="https://crg.eti.br/pub/feliz-2025-com-fogos-de-artificio-no-terminal-com-golang/fireworks-em-golang_hu_540d81dfb0c7b7ac.webp">
&lt;source media="(max-width: 1080px)" srcset="https://crg.eti.br/pub/feliz-2025-com-fogos-de-artificio-no-terminal-com-golang/fireworks-em-golang_hu_a9d6cf735954d9aa.webp">
&lt;img alt="fireworks in Go" src="https://crg.eti.br/pub/feliz-2025-com-fogos-de-artificio-no-terminal-com-golang/fireworks-em-golang_hu_87a35e7dddfadd11.webp" height="1532" width="2188" loading="lazy" decoding="async">
&lt;/picture>
&lt;/a>&lt;/figure>&lt;p>We use &lt;code>os.Stdout.WriteString&lt;/code> to write directly to the stdout descriptor, that is, the terminal&amp;rsquo;s standard output. This is the fastest way to write to the terminal, but it is not synchronized. That means there is no guarantee the output will be written in the expected order. In our case, though, this is desirable because it lets the fireworks overlap, giving the impression that they are exploding simultaneously.&lt;/p></description></item><item><title>Rewriting the Old TSR Using Bash</title><link>https://crg.eti.br/pub/reescrevendo-velho-tsr-usando-bash/</link><pubDate>Sat, 21 Dec 2024 17:26:25 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/reescrevendo-velho-tsr-usando-bash/</guid><description>&lt;p>When I started programming, computing was different from today. The operating system was single-tasking; only one program could run at a time. There were no modern features like protected and mapped memory. Even so, it was possible to create concurrent behavior in programs, but you had to be careful to keep any part from blocking execution. For example, there could be no loops waiting for keyboard input or very long processes. Writing a non-blocking program was tricky in languages like Clipper.&lt;/p></description></item><item><title>Deploying an API Behind a Reverse Proxy with Caddyserver and Go</title><link>https://crg.eti.br/pub/subindo-api-via-proxy-reverso-caddy-go/</link><pubDate>Fri, 20 Dec 2024 01:34:17 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/subindo-api-via-proxy-reverso-caddy-go/</guid><description>&lt;p>A friend asked me for an example of how to deploy an API behind a reverse proxy using Go. Here is a short walkthrough.&lt;/p>
&lt;p>First, set up a server and register its IP with your DNS provider. Assign the IP to a name so you can create an HTTPS certificate for the machine.&lt;/p>
&lt;p>Configure the machine&amp;rsquo;s firewall and open only ports 22 (SSH), 80 (HTTP), and 443 (HTTPS).&lt;/p>
&lt;h2 id="caddy">Caddy&lt;/h2>
&lt;p>I use the Caddy HTTP server. It is practical and creates HTTPS certificates automatically. By default, it redirects HTTP requests to HTTPS.&lt;/p></description></item><item><title>Benchmark: Named vs Explicit Returns in Go</title><link>https://crg.eti.br/pub/benchmark-retornos-nomeados-vs-explicitos-go/</link><pubDate>Tue, 17 Dec 2024 03:00:24 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/benchmark-retornos-nomeados-vs-explicitos-go/</guid><description>&lt;p>A question came up in our Go study group: are named returns faster than explicit returns? That was the hypothesis.&lt;/p>
&lt;p>Fortunately, Go has good tools to test this.&lt;/p>
&lt;p>Let&amp;rsquo;s write some code with two sum functions: one with named returns and one with explicit returns.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">package&lt;/span> &lt;span style="color:#1f2328">main&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;testing&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">// Função com retornos nomeados&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#6639ba">somaNomeados&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">a&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">b&lt;/span> &lt;span style="color:#cf222e">int&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">resultado&lt;/span> &lt;span style="color:#cf222e">int&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#cf222e">error&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">resultado&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">a&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#1f2328">b&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">// Função com retornos explícitos&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#6639ba">somaExplicitos&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">a&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">b&lt;/span> &lt;span style="color:#cf222e">int&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">int&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">error&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">a&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#1f2328">b&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Next, we create the benchmark functions. The names of these functions matter. Go&amp;rsquo;s testing tool looks for functions that start with &amp;ldquo;Benchmark&amp;rdquo;.&lt;/p></description></item><item><title>Writing About Computer Programming</title><link>https://crg.eti.br/pub/escrevendo-sobre-programacao-de-computadores/</link><pubDate>Sun, 15 Dec 2024 17:29:11 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/escrevendo-sobre-programacao-de-computadores/</guid><description>&lt;p>Writing about programming and computing is challenging. These topics are complex, and it is hard to build a narrative that is both understandable and interesting.&lt;/p>
&lt;p>On top of that, Portuguese is a demanding language. I tend to write the way I speak, which results in texts that are hard to read.&lt;/p>
&lt;p>To make things easier, I created a few rules that serve as a guide. They are not strict, just guidelines in no particular order.&lt;/p></description></item><item><title>Customizing Neovim: Sorting and Removing Duplicate Lines with Lua</title><link>https://crg.eti.br/pub/personalizando_neovim_ordenacao_e_remocao_de_linhas_duplicadas_com_lua/</link><pubDate>Fri, 29 Nov 2024 00:31:30 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/personalizando_neovim_ordenacao_e_remocao_de_linhas_duplicadas_com_lua/</guid><description>&lt;p>Continuing my Neovim customizations, here are two functions I use frequently: &lt;code>sort_lines&lt;/code> and &lt;code>sort_and_uniq_lines&lt;/code>. As the names suggest, they sort the content of the selected lines and, in the case of &lt;code>sort_and_uniq_lines&lt;/code>, also remove duplicates.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-lua" data-lang="lua">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">sort_lines&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">-- Get the start and end position of the selection&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> start_pos &lt;span style="color:#0550ae">=&lt;/span> vim.fn&lt;span style="color:#1f2328">.&lt;/span>getpos&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&amp;#39;&amp;lt;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> end_pos &lt;span style="color:#0550ae">=&lt;/span> vim.fn&lt;span style="color:#1f2328">.&lt;/span>getpos&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&amp;#39;&amp;gt;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">-- Convert the position to the line index&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">-- Adjust start_pos because lines in Lua start at 0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> start_line &lt;span style="color:#0550ae">=&lt;/span> start_pos&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">-&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">-- No need to adjust end_line&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> end_line &lt;span style="color:#0550ae">=&lt;/span> end_pos&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">-- Get the selected lines&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> lines &lt;span style="color:#0550ae">=&lt;/span> vim.api&lt;span style="color:#1f2328">.&lt;/span>nvim_buf_get_lines&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> start_line&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> end_line&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">false&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">-- Sort the lines&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> table.sort&lt;span style="color:#1f2328">(&lt;/span>lines&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">-- Replace the original lines&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> vim.api&lt;span style="color:#1f2328">.&lt;/span>nvim_buf_set_lines&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> start_line&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> end_line&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> lines
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">sort_and_uniq_lines&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> start_pos &lt;span style="color:#0550ae">=&lt;/span> vim.fn&lt;span style="color:#1f2328">.&lt;/span>getpos&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&amp;#39;&amp;lt;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> end_pos &lt;span style="color:#0550ae">=&lt;/span> vim.fn&lt;span style="color:#1f2328">.&lt;/span>getpos&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&amp;#39;&amp;gt;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> start_line &lt;span style="color:#0550ae">=&lt;/span> start_pos&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">-&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> end_line &lt;span style="color:#0550ae">=&lt;/span> end_pos&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> lines &lt;span style="color:#0550ae">=&lt;/span> vim.api&lt;span style="color:#1f2328">.&lt;/span>nvim_buf_get_lines&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> start_line&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> end_line&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">false&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> table.sort&lt;span style="color:#1f2328">(&lt;/span>lines&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">-- Remove duplicate lines&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> uniq_lines &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">local&lt;/span> last_line &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">for&lt;/span> _&lt;span style="color:#1f2328">,&lt;/span> line &lt;span style="color:#cf222e">in&lt;/span> ipairs&lt;span style="color:#1f2328">(&lt;/span>lines&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> line &lt;span style="color:#0550ae">~=&lt;/span> last_line &lt;span style="color:#cf222e">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> table.insert&lt;span style="color:#1f2328">(&lt;/span>uniq_lines&lt;span style="color:#1f2328">,&lt;/span> line&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> last_line &lt;span style="color:#0550ae">=&lt;/span> line
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> vim.api&lt;span style="color:#1f2328">.&lt;/span>nvim_buf_set_lines&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> start_line&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> end_line&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> uniq_lines
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>vim.api&lt;span style="color:#1f2328">.&lt;/span>nvim_set_keymap&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;v&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;&amp;lt;Leader&amp;gt;s&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;:lua sort_lines()&amp;lt;CR&amp;gt;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span> noremap &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> silent &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>vim.api&lt;span style="color:#1f2328">.&lt;/span>nvim_set_keymap&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;v&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;&amp;lt;Leader&amp;gt;u&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;:lua sort_and_uniq_lines()&amp;lt;CR&amp;gt;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span> noremap &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> silent &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://crg.eti.br/pub/personalizando_neovim_ordenacao_e_remocao_de_linhas_duplicadas_com_lua/sort_lines.lua">sort_lines.lua&lt;/a>&lt;/p></description></item><item><title>Building a Bookmark System in Neovim with Lua</title><link>https://crg.eti.br/pub/criando-sistema-de-bookmarks-no-neovim-com-lua/</link><pubDate>Mon, 25 Nov 2024 00:25:27 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/criando-sistema-de-bookmarks-no-neovim-com-lua/</guid><description>&lt;p>Continuing our series of articles aimed at reducing the cognitive effort involved in programming tasks, here is my small bookmark script for Neovim.&lt;/p>
&lt;p>Neovim is incredibly customizable. Without having to build full plugins, you can add a lot of functionality with just a few Lua functions.&lt;/p>
&lt;p>In my day-to-day work, I often need to return to the same files to fix and test problems. Opening those files directly at the right line, without wasting time navigating, is essential.&lt;/p></description></item><item><title>A Script for Fast Directory Navigation Using fzf</title><link>https://crg.eti.br/pub/script-rapido-navegacao-diretorios-fzf/</link><pubDate>Sun, 24 Nov 2024 15:43:50 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/script-rapido-navegacao-diretorios-fzf/</guid><description>&lt;p>This article presents a script to make directory navigation faster, continuing the series on reducing cognitive complexity.&lt;/p>
&lt;p>You often need to move between several directories in one or many projects. Remembering paths and locating files becomes an unnecessary effort.&lt;/p>
&lt;p>One solution is to keep a list of the most recently visited directories so you can switch between them quickly. Dave Eddy implemented this idea in his &lt;a href="https://github.com/bahamas10/bash-cdstack">cdstack&lt;/a>.&lt;/p>
&lt;p>Inspired by that approach, I built my own version, better suited to the way I work.&lt;/p></description></item><item><title>Reducing Cognitive Complexity in Programming</title><link>https://crg.eti.br/pub/diminuindo-a-complexidade-cognitiva-na-programacao/</link><pubDate>Sat, 23 Nov 2024 21:28:27 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/diminuindo-a-complexidade-cognitiva-na-programacao/</guid><description>&lt;p>I spend a lot of time and effort reducing cognitive complexity when I program.&lt;/p>
&lt;p>Cognitive complexity is how much you have to think to get a task done. Small details can make a task unnecessarily complex.&lt;/p>
&lt;p>For example, finding a snippet of code hidden among many files inside a large directory structure takes effort. Even if the structure is familiar and well designed, the goal is not to navigate through it opening files until you find the code to edit; the goal is simply to edit the code. Anything beyond that is wasted cognitive effort.&lt;/p></description></item><item><title>Restructuring Articles for Clarity and Concision</title><link>https://crg.eti.br/pub/reestruturando-artigos-para-clareza-e-concisao/</link><pubDate>Sat, 23 Nov 2024 19:53:57 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/reestruturando-artigos-para-clareza-e-concisao/</guid><description>&lt;p>I&amp;rsquo;m restructuring how the articles on this site are written.&lt;/p>
&lt;p>I usually write the way I speak, which some people find pleasant. That said, my love-hate relationship with the Portuguese language sometimes makes my texts hard to follow. I also tend to go on too long when explaining reasons and concepts, which makes the text dull.&lt;/p>
&lt;p>As a writing exercise, I&amp;rsquo;m reviewing my texts. I&amp;rsquo;m fixing spelling and grammar problems and making the content more direct.&lt;/p></description></item><item><title>A Virus in the Lab</title><link>https://crg.eti.br/pub/virus-no-laboratorio/</link><pubDate>Fri, 25 Oct 2024 22:43:08 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/virus-no-laboratorio/</guid><description>&lt;p>This story goes back to the first half of the 2000s. At the time I worked at a company that built hardware for telephony.&lt;/p>
&lt;p>It was a lot of fun. I had access to some nice NEC machines and wrote some really interesting code.&lt;/p>
&lt;p>That was when I wrote a VoIP recorder that captured SIP packets directly off the network, in less than 100 lines of C, but that&amp;rsquo;s a story for another day.&lt;/p></description></item><item><title>Programming as Art</title><link>https://crg.eti.br/pub/arte-generativa-em-javascript-segunda-parte/</link><pubDate>Sun, 29 Sep 2024 16:24:25 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/arte-generativa-em-javascript-segunda-parte/</guid><description>&lt;p>I consider programming computers a form of artistic expression. There are many ways to solve everyday programming problems, which leaves plenty of room for creativity.&lt;/p>
&lt;p>&lt;canvas id="grid_rect_canvas" class="genart_full">&lt;/canvas>&lt;/p>
&lt;h2 id="classic-examples-of-generative-art">Classic Examples of Generative Art&lt;/h2>
&lt;p>And there are many interesting examples of computer-generated art. My favorites are the &amp;ldquo;one-liners&amp;rdquo;, programs of just a single line that do interesting things, like the famous &lt;code>10 PRINT CHR$ (205.5 + RND (1)); : GOTO 10&lt;/code> that draws a maze using &lt;em>BASIC&lt;/em>, and the more modern equivalent &lt;code>yes 'c=(╱ ╲);printf ${c[RANDOM%2]}'|bash&lt;/code> written in &lt;em>Bash&lt;/em>. A quick search on the internet will turn up several implementations in different languages.&lt;/p></description></item><item><title>Generative Art in JavaScript for the Sides of the Site</title><link>https://crg.eti.br/pub/arte-generativa-em-javascript/</link><pubDate>Sun, 25 Aug 2024 18:35:45 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/arte-generativa-em-javascript/</guid><description>&lt;p>After a long time, I finally added some JavaScript to this site.&lt;/p>
&lt;p>I have a huge mental block when it comes to web technologies. JavaScript, CSS, and even HTML itself feel very improvised to me, especially the whole idea of the &amp;ldquo;single page application&amp;rdquo;.&lt;/p>
&lt;p>This is a limitation I need to get over. After all, these days the web really is the best and most portable interface for most programs, even though it goes against a lot of what I believe about minimalism and saving resources.&lt;/p></description></item><item><title>Post-Apocalyptic Computing</title><link>https://crg.eti.br/pub/computacao-pos-apocaliptica/</link><pubDate>Sat, 13 Jul 2024 18:17:36 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/computacao-pos-apocaliptica/</guid><description>&lt;p>Post-apocalyptic computing is a game, an interesting exercise for your imagination. The scenario goes like this: something terrible has happened and the society you live in no longer exists. As a survivor, it&amp;rsquo;s up to you to help rebuild modern society.&lt;/p>
&lt;figure class="media-frame media-center fade-in">&lt;a href="https://crg.eti.br/pub/computacao-pos-apocaliptica/computacao-pos-apocaliptica-0.webp">
&lt;picture>
&lt;source media="(max-width: 480px)" srcset="https://crg.eti.br/pub/computacao-pos-apocaliptica/computacao-pos-apocaliptica-0_hu_c3f0f04a4b3b30ce.webp">
&lt;source media="(max-width: 1080px)" srcset="https://crg.eti.br/pub/computacao-pos-apocaliptica/computacao-pos-apocaliptica-0_hu_c263a07ecdd35615.webp">
&lt;img alt="Post-apocalyptic computing" src="https://crg.eti.br/pub/computacao-pos-apocaliptica/computacao-pos-apocaliptica-0_hu_371655508fb5b573.webp" height="200" width="200" loading="lazy" decoding="async">
&lt;/picture>
&lt;/a>&lt;/figure>&lt;p>The cause of the apocalypse can be whatever you like: nuclear war, plague, economic collapse, a solar storm, an oppressive government that wants to keep technology to itself, and so on. The only constant is that nothing you take for granted is available. All the infrastructure is gone. There&amp;rsquo;s no more running water, no electricity, none of the amenities of modern life.&lt;/p></description></item><item><title>Building My Own System to Tell Time</title><link>https://crg.eti.br/pub/internet-time/</link><pubDate>Thu, 16 May 2024 11:39:44 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/internet-time/</guid><description>&lt;p>Measuring time is a serious task, and more complicated than it seems. Like any good nerd, I&amp;rsquo;m fascinated by the many ways of measuring and counting time. One that really catches my attention is &amp;ldquo;&lt;a href="https://en.wikipedia.org/wiki/Decimal_time">decimal time&lt;/a>&amp;rdquo;.&lt;/p>
&lt;p>There are several implementations of decimal time, usually dividing the day into 10 hours of 100 minutes each. Another approach is to ignore hours altogether and use only minutes as a continuous number. If you need more precision, you just use fractions of that minute, with as many decimal places as you need.&lt;/p></description></item><item><title>Deploying Applications Using curl</title><link>https://crg.eti.br/pub/deploy_de_aplicacoes_usando_curl/</link><pubDate>Sat, 09 Mar 2024 11:45:51 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/deploy_de_aplicacoes_usando_curl/</guid><description>&lt;p>Small teams face several challenges when distributing binaries these days. If you simply put an application up for download on a website, search tools will immediately flag your site as suspicious content. Browsers show the user a scary warning, and there is no way to remove it, even with a signed binary. The warning only goes away once enough users have downloaded your binary without reporting problems.&lt;/p>
&lt;p>Letting the user download the binary from some already well-known site, even GitHub, isn&amp;rsquo;t ideal, especially for closed-source applications.&lt;/p></description></item><item><title>ps - process hierarchy</title><link>https://crg.eti.br/pub/hierarquia-de-processos/</link><pubDate>Sun, 11 Feb 2024 14:13:47 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/hierarquia-de-processos/</guid><description>&lt;p>When I started using &lt;a href="https://github.com/crgimenes/compterm">compterm&lt;/a>, a problem soon appeared: sometimes I forgot that compterm was loaded. So I wrote a small function to detect whether I was in a session started by compterm or just a regular zsh session.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> is_parent_compterm &lt;span style="color:#0550ae">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">local&lt;/span> &lt;span style="color:#953800">pid&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#953800">$$&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">local&lt;/span> parent_pid
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">while&lt;/span> &lt;span style="color:#0550ae">[&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#953800">$pid&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span> -ne &lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#0550ae">]&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#cf222e">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">parent_pid&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>ps -p &lt;span style="color:#953800">$pid&lt;/span> -o &lt;span style="color:#953800">ppid&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#cf222e">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">parent_pid&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">${&lt;/span>&lt;span style="color:#953800">parent_pid&lt;/span>&lt;span style="color:#1f2328">//[[:&lt;/span>&lt;span style="color:#953800">blank&lt;/span>&lt;span style="color:#1f2328">:]]/&lt;/span>&lt;span style="color:#0a3069">}&lt;/span> &lt;span style="color:#57606a"># Remove espaços&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># Verifica se o nome do comando do processo pai é &amp;#39;compterm&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> ps -p &lt;span style="color:#953800">$parent_pid&lt;/span> -o &lt;span style="color:#953800">comm&lt;/span>&lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">|&lt;/span> grep -q &lt;span style="color:#0a3069">&amp;#34;^compterm&lt;/span>$&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#cf222e">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0550ae">0&lt;/span> &lt;span style="color:#57606a"># Retorna true se encontrar &amp;#39;compterm&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">pid&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#953800">$parent_pid&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">done&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#57606a"># Retorna false se &amp;#39;compterm&amp;#39; não for encontrado&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This function walks through all the parent processes of the current process, and if any of them is named compterm, it returns true. With that I can customize the prompt and tell whether compterm is loaded or not.&lt;/p></description></item><item><title>Studying Assembly</title><link>https://crg.eti.br/pub/estudando-assembly/</link><pubDate>Sat, 22 Jul 2023 10:47:36 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/estudando-assembly/</guid><description>&lt;p>When I started programming, back in the 8-bit era, learning a bit of assembly was unavoidable. The machines were far simpler than today&amp;rsquo;s computers, and we often didn&amp;rsquo;t even have a compiler at hand. Instead, we typed small chunks of opcodes directly in hexadecimal.&lt;/p>
&lt;p>This was incredibly useful for working around the limitations of the BASIC that served both as a programming language and as the operating system (burned straight into the machine&amp;rsquo;s ROM).&lt;/p></description></item><item><title>Hidden Files on UNIX</title><link>https://crg.eti.br/pub/arquivos-ocultos-no-unix/</link><pubDate>Mon, 15 May 2023 06:21:48 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/arquivos-ocultos-no-unix/</guid><description>&lt;p>Everyone knows how to create hidden files in the UNIX/Linux world: just start the file name with a dot (.). But this feature wasn&amp;rsquo;t always there.&lt;/p>
&lt;p>According to Rob Pike in a Google+ post that is now only available on archive.org, around version 2 of UNIX, while the Unix file system design was being worked on, the &amp;ldquo;.&amp;rdquo; and &amp;ldquo;..&amp;rdquo; entries appeared to make directory navigation easier. This probably happened in version 2, when the file system became hierarchical.&lt;/p></description></item><item><title>Why Is My Site So Ugly?</title><link>https://crg.eti.br/pub/por-que-meu-site-eh-tao-feio/</link><pubDate>Sun, 23 Apr 2023 10:29:39 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/por-que-meu-site-eh-tao-feio/</guid><description>&lt;h2 id="update">Update&lt;/h2>
&lt;p>I was recently convinced to try a more modern theme, so I&amp;rsquo;m experimenting with a new one while keeping the same philosophy of accessibility and simplicity. And, for a change, a light theme. On top of that, I added some JavaScript, as incredible as that may sound.&lt;/p>
&lt;hr>
&lt;p>There&amp;rsquo;s always someone asking why my site is so ugly. It has sparked plenty of laughs and usually serves as a hook for good conversations. But since I&amp;rsquo;ve been asked about it so many times, it&amp;rsquo;s worth leaving a written answer for anyone who isn&amp;rsquo;t close enough (or shameless enough) to ask me directly.&lt;/p></description></item><item><title>AI-Assisted Programming</title><link>https://crg.eti.br/pub/programacao-assistida-por-ia/</link><pubDate>Sat, 22 Apr 2023 09:33:12 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/programacao-assistida-por-ia/</guid><description>&lt;p>We have recently seen an explosion in the use of artificial intelligence (AI), with products like ChatGPT, GitHub Copilot, Tabnine, and many others. They are very useful and interesting tools, but not as much as the media claims.&lt;/p>
&lt;p>Think of these tools as a machine that predicts which word is most likely to come next, adds it to the suggestion, and does this repeatedly in a loop until it reaches a certain number of words or until the probability of a good guess drops below an acceptable threshold, whichever comes first.&lt;/p></description></item><item><title>Writing Software That Lasts</title><link>https://crg.eti.br/pub/escrevendo-software-para-durar/</link><pubDate>Fri, 21 Apr 2023 16:28:48 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/escrevendo-software-para-durar/</guid><description>&lt;p>Here I&amp;rsquo;ll present some topics that I believe are important when developing software so that it&amp;rsquo;s highly resilient and lasts for many years. The topics are in no particular order and reflect my opinion, grounded in my experience as a developer.&lt;/p>
&lt;p>Treat this text as a collection of ideas I&amp;rsquo;ve gathered over the years. I tried to keep them as generic as possible, but I don&amp;rsquo;t claim they apply to every scenario. I think they fit best if your team is small and you need to ship fast.&lt;/p></description></item><item><title>Go and Rounding Errors</title><link>https://crg.eti.br/pub/golang-erro-de-arredondamento/</link><pubDate>Wed, 12 Apr 2023 09:24:13 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/golang-erro-de-arredondamento/</guid><description>&lt;p>When we write programs that deal with money, the ideal approach is to always use cents. That way we can use integer variables, and it&amp;rsquo;s much easier to prevent errors caused by &lt;a href="https://en.wikipedia.org/wiki/IEEE_754">how computers store floating-point numbers&lt;/a>.&lt;/p>
&lt;p>But we don&amp;rsquo;t always get to choose. When we consume third-party &lt;em>APIs&lt;/em>, for example, best practices aren&amp;rsquo;t always followed. In fact, in day-to-day work, ideal conditions are a rarity.&lt;/p>
&lt;p>Not long ago I ran into a problem like this: an &lt;em>API&lt;/em> my system needed to consume returned a &lt;em>JSON&lt;/em> where the value field was not only a string but also a floating-point number.&lt;/p></description></item><item><title>Go and the promise of backward compatibility</title><link>https://crg.eti.br/pub/golang-retrocompatibilidade/</link><pubDate>Wed, 12 Apr 2023 09:24:13 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/golang-retrocompatibilidade/</guid><description>&lt;p>When version 1.0 of the Go language was released, its developers made a &lt;a href="https://go.dev/doc/go1compat">commitment to maintain backward compatibility&lt;/a> as new versions came out.&lt;/p>
&lt;p>This commitment brings several interesting results. For example, the code you learn doesn&amp;rsquo;t become outdated. On top of that, keeping the language backward compatible reinforces another important commitment: simplicity and readability of code. That project that sat untouched for months, maybe years, still compiles on the first try. I experienced this personally with code that &lt;em>sat in a drawer&lt;/em> for three years.&lt;/p></description></item><item><title>CPBR14, Wardriving</title><link>https://crg.eti.br/pub/cpbr14/</link><pubDate>Tue, 08 Nov 2022 08:55:30 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/cpbr14/</guid><description>&lt;p>Useful links for the workshop &amp;ldquo;Wardriving - A brief introduction, equipment, and software&amp;rdquo; at Campus Party Brazil 2022.&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://wigle.net/">WiGLE Wifi Wardriving&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://apps.apple.com/br/app/gps-2-ip/id408625926">GPS2IP&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/tiagoshibata/Android-GPSd-Forwarder">Android GPSd Forwarder&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.kismetwireless.net/">Kismet Wireless&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://discord.gg/cyberdeck-cafe-607459933784637460">Cyberdeck Cafe&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>&lt;a href="https://crg.eti.br/en/cesar-gimenes">Cesar Gimenes&lt;/a>&lt;/p></description></item><item><title>Phone GPS on the Raspberry Pi</title><link>https://crg.eti.br/pub/gps-celular-na-raspberry-pi/</link><pubDate>Thu, 08 Sep 2022 01:46:48 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/gps-celular-na-raspberry-pi/</guid><description>&lt;p>I need the &lt;em>Raspberry Pi&lt;/em> I carry in my backpack to have access to GPS coordinates, but the USB GPS units and other models available for the &lt;em>Raspberry&lt;/em> are too unreliable and expensive.&lt;/p>
&lt;p>The solution is to use the phone&amp;rsquo;s GPS and share the data with the rest of the gear. This has several advantages: the phone&amp;rsquo;s GPS is excellent, it has usually already locked onto a few satellites, and on top of that I already have it on me, so I don&amp;rsquo;t have to buy anything extra.&lt;/p></description></item><item><title>tr - A Utility for Replacing Characters</title><link>https://crg.eti.br/pub/tr-substituindo-caracteres/</link><pubDate>Sun, 28 Aug 2022 18:42:40 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/tr-substituindo-caracteres/</guid><description>&lt;p>This is a simple and very useful utility. Basically, &lt;code>tr&lt;/code> filters strings one character at a time, and when used correctly it is even UTF-8 compatible.&lt;/p>
&lt;p>Character filtering is defined by the parameters, and to make things easier you can use character &lt;em>classes&lt;/em>, for example &lt;code>[:upper:]&lt;/code> for all uppercase letters or &lt;code>[:cntrl:]&lt;/code> for all control characters.&lt;/p>
&lt;h2 id="parameters">Parameters&lt;/h2>
&lt;p>The parameters I use most are the following:&lt;/p>
&lt;ul>
&lt;li>&lt;code>-d&lt;/code> &lt;em>delete&lt;/em> to remove characters.&lt;/li>
&lt;li>&lt;code>-s&lt;/code> &lt;em>squeeze&lt;/em>, which is quite handy for collapsing sequences of repeated characters.&lt;/li>
&lt;/ul>
&lt;h2 id="examples">Examples&lt;/h2>
&lt;p>Converts uppercase to lowercase, but fails with UTF-8 characters.&lt;/p></description></item><item><title>fmt - A Simple Text Formatting Utility</title><link>https://crg.eti.br/pub/fmt-formatando-texto/</link><pubDate>Tue, 23 Aug 2022 01:04:14 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/fmt-formatando-texto/</guid><description>&lt;p>The &lt;code>fmt&lt;/code> utility is a simple, fast text formatter. Its purpose is to format text files or strings received via stdin so that lines don&amp;rsquo;t exceed the maximum number of characters per line defined by the user.&lt;/p>
&lt;p>It was originally intended to be used together with the mail utility, but it can be useful alongside other programs such as vim, for example.&lt;/p>
&lt;p>The main parameters are:&lt;/p>
&lt;ul>
&lt;li>&lt;code>-w&lt;/code>, which sets the desired number of characters per line.&lt;/li>
&lt;li>&lt;code>-t&lt;/code>, which sets the tab width.&lt;/li>
&lt;/ul>
&lt;p>There are several other useful parameters; check your system&amp;rsquo;s &lt;em>manpage&lt;/em> to learn more.&lt;/p></description></item><item><title>Socket Client and Server in Golang: A Chat Example</title><link>https://crg.eti.br/pub/golang-cliente-servidor-socket-chat/</link><pubDate>Sun, 21 Aug 2022 09:35:32 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/golang-cliente-servidor-socket-chat/</guid><description>&lt;p>This is the fourth version of our socket client and server. In this version, I made some interesting improvements. We now have a complete chat system with useful commands and a few optimizations.&lt;/p>
&lt;p>The goal of this version is to refine the system. I removed one of the write channels to send data directly, increasing efficiency. I also dropped the automatic reconnection to keep the code cleaner, since I added several new features.&lt;/p></description></item><item><title>Assembly on macOS M1/ARM64.</title><link>https://crg.eti.br/pub/assembly-m1/</link><pubDate>Sun, 14 Aug 2022 11:26:49 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/assembly-m1/</guid><description>&lt;p>Here is the story. I had found a great deal on two early-90s computers still running &lt;a href="https://en.wikipedia.org/wiki/Zilog_Z80">Zilog Z80&lt;/a> processors. They weren&amp;rsquo;t in perfect shape, but the price was fine.&lt;/p>
&lt;p>Then a good friend, with far more common sense than me, advised me to stop wasting energy and money on old hardware. To cool down this nerd fever, he suggested I study ARM assembly instead, since it could at least be useful.&lt;/p></description></item><item><title>Socket client and server in Golang with signal handling.</title><link>https://crg.eti.br/pub/golang-cliente-servidor-socket-signals/</link><pubDate>Fri, 12 Aug 2022 00:30:22 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/golang-cliente-servidor-socket-signals/</guid><description>&lt;p>Continuing our series of articles about client/server, we will add a new channel to the &lt;a href="../golang-cliente-servidor-socket-ping-pong">previous example&lt;/a>. This channel will handle signals sent by the operating system.&lt;/p>
&lt;p>The operating system sends signals to programs to manage processes. For example, when you press &lt;em>Ctrl+C&lt;/em>, the operating system sends the SIGINT signal, telling the program that the user wants to interrupt it.&lt;/p>
&lt;p>By default, the program is closed. However, we can intercept this signal and act accordingly. In this case, we will simply terminate the program. In real systems, this feature can be used to save information before closing, stop other processes, close connections and files, and so on. This process is known as &lt;em>graceful shutdown&lt;/em>.&lt;/p></description></item><item><title>Socket Client and Server in Golang with Ping and Pong.</title><link>https://crg.eti.br/pub/golang-cliente-servidor-socket-ping-pong/</link><pubDate>Thu, 11 Aug 2022 00:55:54 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/golang-cliente-servidor-socket-ping-pong/</guid><description>&lt;p>Continuing the &lt;a href="../golang-cliente-servidor-socket-com-canais-e-goroutines">conversation about a resilient client and server&lt;/a>, it&amp;rsquo;s time to improve the server and add the sending of &lt;em>ping&lt;/em> or &lt;em>keep alive&lt;/em> messages.&lt;/p>
&lt;p>We also made improvements to the server. Now, just like the client, it uses goroutines and channels.&lt;/p>
&lt;h2 id="server">Server&lt;/h2>
&lt;h3 id="reading-from-the-connection">Reading from the Connection&lt;/h3>
&lt;p>In this version, the server uses one goroutine to write and another to read the data from the client connection. When using goroutines and channels this way, it&amp;rsquo;s essential to make sure the goroutines are properly terminated.&lt;/p></description></item><item><title>Socket client and server in Golang with goroutines and channels.</title><link>https://crg.eti.br/pub/golang-cliente-servidor-socket-com-canais-e-goroutines/</link><pubDate>Sun, 07 Aug 2022 23:47:50 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/golang-cliente-servidor-socket-com-canais-e-goroutines/</guid><description>&lt;p>Continuing the &lt;a href="../golang-cliente-servidor-socket">example about a persistent socket client in Golang&lt;/a>, I made a few changes to the source code to show how to improve our code and make it asynchronous. To do that, we&amp;rsquo;ll use goroutines and channels.&lt;/p>
&lt;h2 id="goroutines-and-channels">Goroutines and Channels&lt;/h2>
&lt;p>Goroutines and channels are advanced features of the Go language. Goroutines are lightweight threads managed by the language runtime itself, and channels allow communication between goroutines.&lt;/p>
&lt;p>In our case, we&amp;rsquo;ll use channels for communication between the goroutines in our program.&lt;/p></description></item><item><title>Socket Client and Server in Golang.</title><link>https://crg.eti.br/pub/golang-cliente-servidor-socket/</link><pubDate>Wed, 03 Aug 2022 07:36:17 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/golang-cliente-servidor-socket/</guid><description>&lt;p>In the Go study group, a question came up about how to write a persistent client that reconnects to a socket server whenever the connection fails.&lt;/p>
&lt;p>The main difficulty people seem to have is understanding the concept of a state machine. So we&amp;rsquo;ll build a few examples of a persistent client, starting with a simple state machine, without goroutines or channels.&lt;/p>
&lt;p>Before that, we&amp;rsquo;ll create a small socket server for our client to connect to: the famous echo server.&lt;/p></description></item><item><title>Make Your Linux Less Secure and Slightly Faster</title><link>https://crg.eti.br/pub/linux-mais-rapido-menos-seguro/</link><pubDate>Sun, 26 Jun 2022 17:07:57 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/linux-mais-rapido-menos-seguro/</guid><description>&lt;p>First, of course, don&amp;rsquo;t hold me responsible for what you do to your system — the responsibility is entirely yours.&lt;/p>
&lt;p>There are several processing strategies that, despite producing a substantial performance gain, ended up introducing security flaws. What I did was take two machines from my cluster and configure the &lt;em>Linux kernel&lt;/em> not to disable those features.&lt;/p>
&lt;p>In my case, since I use Debian, I edited the file &lt;code>/etc/default/grub&lt;/code> and added &lt;code>mitigations=off&lt;/code> at the end of the &lt;code>GRUB_CMDLINE_LINUX_DEFAULT&lt;/code> variable.&lt;/p></description></item><item><title>Remote Clipboard</title><link>https://crg.eti.br/pub/area-de-transferencia-remota/</link><pubDate>Tue, 01 Mar 2022 10:36:45 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/area-de-transferencia-remota/</guid><description>&lt;p>&lt;em>Tip:&lt;/em> The &lt;code>pbcopy&lt;/code> command on the Mac is equivalent to &lt;code>xclip -selection clipboard&lt;/code> on Linux. The &lt;code>pbpaste&lt;/code> command on the Mac matches &lt;code>xclip -selection clipboard -o&lt;/code> on Linux. The &lt;code>xclip&lt;/code> command doesn&amp;rsquo;t work because it requires &lt;a href="https://en.wikipedia.org/wiki/X_Window_System">X Window&lt;/a> installed.&lt;/p>
&lt;h2 id="copy-and-paste">Copy and Paste&lt;/h2>
&lt;p>I edit a lot of code on remote servers over SSH, with no graphical interface, usually with &lt;a href="https://neovim.io">Neovim&lt;/a>. It would be great to copy and paste between the remote machine and the local one. Pasting from the local machine to the remote one is simple, since the terminal already handles it. Copying from the remote machine to the local one, however, takes a bit of code.&lt;/p></description></item><item><title>Speeding Up the Site</title><link>https://crg.eti.br/pub/acelerando-o-site/</link><pubDate>Sun, 30 Jan 2022 16:00:03 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/acelerando-o-site/</guid><description>&lt;p>To share my articles over &lt;a href="https://ipfs.io">IPFS&lt;/a>, it made sense to embed the CSS and images directly into the HTML so that there would be a single file to share.&lt;/p>
&lt;p>Embedding the CSS was the simplest part: I just placed the CSS directly into the site template using the &lt;code>&amp;lt;style&amp;gt;&amp;lt;/style&amp;gt;&lt;/code> &lt;em>tag&lt;/em>, and embedding the CSS alone already produced a nice speed gain.&lt;/p>
&lt;p>I use &lt;a href="https://gohugo.io">HUGO&lt;/a> as the &lt;em>framework&lt;/em> to generate the site automatically. HUGO works by converting pages written in &lt;em>Markdown&lt;/em>, but the same idea applies no matter how the site is built, even if it is written by hand, directly in HTML. With HUGO and a bit of programming, though, it was easy to automate my template and have the images converted to &lt;em>Base64&lt;/em> and inserted into the page automatically.&lt;/p></description></item><item><title>How to Extend Git</title><link>https://crg.eti.br/pub/git-como-estender/</link><pubDate>Mon, 25 Oct 2021 14:20:09 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/git-como-estender/</guid><description>&lt;p>Git is an extremely flexible tool and very simple to extend and build features on. To create a command, you just need an executable named git-&lt;strong>command&lt;/strong> (&lt;em>git dash followed by the command name&lt;/em>).&lt;/p>
&lt;p>Any executable on the PATH that follows this naming pattern will be called by git. To start with a simple example, let&amp;rsquo;s do the traditional &amp;ldquo;hello world&amp;rdquo;. Save the example below as &lt;code>git-hello&lt;/code> in a directory on the PATH.&lt;/p></description></item><item><title>Headless VirtualBox</title><link>https://crg.eti.br/pub/headless-virtualbox/</link><pubDate>Sat, 02 Oct 2021 00:25:33 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/headless-virtualbox/</guid><description>&lt;p>&lt;strong>WIP - This text is a work in progress. I haven&amp;rsquo;t documented all the examples I wanted to yet, nor have I reviewed the text. Contributions are welcome.&lt;/strong>&lt;/p>
&lt;p>Continuing with the project of building a machine &lt;em>cluster&lt;/em>, I&amp;rsquo;m going to need some kind of virtualization system, because not all of the experiments I want to run can be done with containers alone. I did a few tests with &lt;a href="https://www.qemu.org">QEMU&lt;/a>, but for now it&amp;rsquo;s more practical to &lt;em>stick&lt;/em> with &lt;a href="https://www.virtualbox.org">VirtualBox&lt;/a>.&lt;/p></description></item><item><title>How to Shrink Your Container Using Multi-Stage Builds</title><link>https://crg.eti.br/pub/docker-multi-stage-build/</link><pubDate>Thu, 17 Jun 2021 20:52:35 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/docker-multi-stage-build/</guid><description>&lt;p>Every now and then I run into some huge Docker image where 99% of the size is junk left behind while the image was being built. This is especially bad when we&amp;rsquo;re dealing with Go executables, which are self-contained and usually don&amp;rsquo;t need any external resources, not even libc.&lt;/p>
&lt;h2 id="multi-stage-builds">multi-stage builds&lt;/h2>
&lt;p>The solution is to use &lt;em>multi-stage builds&lt;/em>. This way you can have two stages in your Dockerfile: a build stage that downloads whatever is needed, compiles the code, and so on, and another that just copies the executables and resources to their expected locations. This second stage doesn&amp;rsquo;t even need to be based on a distribution; it can be a &lt;em>scratch&lt;/em> image, which shrinks the final size even further.&lt;/p></description></item><item><title>auto-cpufreq: dynamically adjusting CPU frequency</title><link>https://crg.eti.br/pub/auto-cpufreq/</link><pubDate>Thu, 03 Jun 2021 21:24:42 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/auto-cpufreq/</guid><description>&lt;p>&lt;a href="https://github.com/AdnanHodzic/auto-cpufreq">auto-cpufreq&lt;/a> optimizes CPU frequency and reacts quite fast. It&amp;rsquo;s great for stretching battery life on a Linux laptop.&lt;/p>
&lt;p>In my case, I use it to keep my small home server at a milder temperature, and in practice I haven&amp;rsquo;t noticed any real impact. There&amp;rsquo;s a bit of latency when the machine is &amp;ldquo;cold&amp;rdquo; and I suddenly start some heavy process, like opening an SSH+mosh+zsh session.&lt;/p>
&lt;h2 id="installation">Installation&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git clone https://github.com/AdnanHodzic/auto-cpufreq.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">cd&lt;/span> auto-cpufreq
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo ./auto-cpufreq-installer
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Track CPU core frequency and temperature with the following command&lt;/p></description></item><item><title>First steps when setting up a new server</title><link>https://crg.eti.br/pub/configurando-novo-servidor/</link><pubDate>Mon, 03 May 2021 18:30:30 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/configurando-novo-servidor/</guid><description>&lt;p>Whenever I bring up a new machine I always run a few commands and set up some configuration. A lot of it is already handled by my &lt;a href="https://github.com/crgimenes/dotfiles">dotfiles&lt;/a>, but there&amp;rsquo;s always plenty of custom work left to do.&lt;/p>
&lt;p>The first thing is to get SSH access and make sure the root password isn&amp;rsquo;t the default one.&lt;/p>
&lt;p>Next I give my user sudo access, in case it doesn&amp;rsquo;t have it already.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>usermod -aG sudo &lt;span style="color:#0a3069">${&lt;/span>&lt;span style="color:#953800">USER&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If it&amp;rsquo;s a machine on the local network, I set it up to use &lt;a href="https://crg.eti.br/pub/zero-configuration-network-no-debian/">zero configuration network&lt;/a>, a much more convenient way to reach the machine, especially on IPv6 networks. Otherwise, this is a good time to add the machine to a domain.&lt;/p></description></item><item><title>The UNIX Manual</title><link>https://crg.eti.br/pub/o-manual-do-unix/</link><pubDate>Wed, 10 Feb 2021 06:45:14 +0000</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/o-manual-do-unix/</guid><description>&lt;p>On November 3, 1971, the first version of the &lt;a href="https://www.bell-labs.com/usr/dmr/www/1stEdman.html">Unix Programmer&amp;rsquo;s Manual&lt;/a> was released, commonly known as man pages.&lt;/p>
&lt;p>You can download it as PDF or PostScript from &lt;a href="https://www.bell-labs.com/usr/dmr/www/">Dennis Ritchie&amp;rsquo;s page at Bell Labs&lt;/a>, maintained by Nokia for historical reasons.&lt;/p>
&lt;p>It&amp;rsquo;s interesting how UNIX commands haven&amp;rsquo;t changed much over the years. If you&amp;rsquo;re a Linux or BSD user, you&amp;rsquo;ll certainly recognize most of them. It&amp;rsquo;s also remarkable how such a simple idea can be so incredibly useful.&lt;/p></description></item><item><title>A find command tip</title><link>https://crg.eti.br/pub/dica-do-comando-find/</link><pubDate>Wed, 14 Oct 2020 06:45:14 +0000</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/dica-do-comando-find/</guid><description>&lt;p>I use the find command a lot to look for files, whether in bash scripts or straight from the command line.&lt;/p>
&lt;p>An interesting trick is excluding some files from the list. For example, I recently needed to look for all &amp;ldquo;.md&amp;rdquo; files but wanted to exclude everything starting with an underscore, as well as the &amp;ldquo;default.md&amp;rdquo; file.&lt;/p>
&lt;p>To do that I used the &lt;em>-not&lt;/em> parameter before the &lt;em>-name&lt;/em> parameter, as in the example below.&lt;/p></description></item><item><title>Setting HTTP Request Timeouts in Golang</title><link>https://crg.eti.br/pub/go-http-timeout/</link><pubDate>Sun, 04 Oct 2020 10:41:09 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/go-http-timeout/</guid><description>&lt;p>By default, Go doesn&amp;rsquo;t set timeouts for HTTP requests, which can cause a number of problems and vulnerabilities. A DOS attack, for example, could simply open a large number of connections to your server.&lt;/p>
&lt;p>To fix this, create an instance of the &lt;code>http.Server&lt;/code> struct and fill in the &lt;code>WriteTimeout&lt;/code> and &lt;code>ReadTimeout&lt;/code> fields with values you consider appropriate.&lt;/p>
&lt;p>Here&amp;rsquo;s an example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-golang" data-lang="golang">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#6639ba">main&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">r&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">mux&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">NewRouter&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#6639ba">StrictSlash&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">r&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">HandleFunc&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">mainHandler&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">srv&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&lt;/span>&lt;span style="color:#1f2328">http&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Server&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">Handler&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">r&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">Addr&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;:8000&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">WriteTimeout&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0550ae">15&lt;/span> &lt;span style="color:#0550ae">*&lt;/span> &lt;span style="color:#1f2328">time&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Second&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">ReadTimeout&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0550ae">15&lt;/span> &lt;span style="color:#0550ae">*&lt;/span> &lt;span style="color:#1f2328">time&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Second&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Listen at port :8000&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Fatal&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">srv&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">ListenAndServe&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This sets the default timeout values for all HTTP requests.&lt;/p></description></item><item><title>Session Control in Golang with Gorilla Sessions</title><link>https://crg.eti.br/pub/go-controle-de-sessao/</link><pubDate>Sat, 03 Oct 2020 22:38:09 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/go-controle-de-sessao/</guid><description>&lt;p>Session control is a fairly old concept: cookies hold some data about the user&amp;rsquo;s session. For security, we usually only keep a UUID in the cookie, as random as possible, which the server then uses to look up other data, such as which user is logged in.&lt;/p>
&lt;p>The UUID needs to be as random as possible, because if someone can predict the next UUID, they can hijack a legitimate user&amp;rsquo;s session.&lt;/p></description></item><item><title>Finding the IP with Golang</title><link>https://crg.eti.br/pub/descobrindo-ip-com-golang/</link><pubDate>Sat, 23 May 2020 10:45:43 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/descobrindo-ip-com-golang/</guid><description>&lt;p>I recently ran into an interesting problem: I needed to stand up a small REST service to manage some hardware, all without human intervention and with multiple network interfaces involved.&lt;/p>
&lt;p>At some point my system has to bring up an auxiliary service and tell the client which IP and port to connect to. Normally you&amp;rsquo;d handle this with a config file somewhere, but one requirement was that I couldn&amp;rsquo;t assume my own IP, since it could come from any of the network interfaces, and making all of that configurable would get too complex.&lt;/p></description></item><item><title>Differences Between Slice and Array in Go</title><link>https://crg.eti.br/pub/diferencas-entre-slices-e-arrays-golang/</link><pubDate>Tue, 14 Apr 2020 11:11:33 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/diferencas-entre-slices-e-arrays-golang/</guid><description>&lt;h2 id="array">Array&lt;/h2>
&lt;p>Arrays in Go always have a fixed size.&lt;/p>
&lt;p>When you add a new element to an array, what happens internally is that a new array is created and the old and new items are copied into it. Eventually the space occupied by the old array gets freed by the garbage collector. So it&amp;rsquo;s important, whenever possible, to declare the array with the maximum size it will need and avoid appending items, especially inside a loop.&lt;/p></description></item><item><title>The Problems with Programming in Golang</title><link>https://crg.eti.br/pub/problemas-programando-em-golang/</link><pubDate>Sun, 01 Mar 2020 11:11:33 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/problemas-programando-em-golang/</guid><description>&lt;p>I love Go. I choose Go for many of my projects. It&amp;rsquo;s simple and robust, with extensive documentation, plenty of examples, and a rich standard library focused on solving today&amp;rsquo;s problems. It&amp;rsquo;s without a doubt an excellent language.&lt;/p>
&lt;p>However, nothing is perfect. Golang has its problems, like any other language. Some will be solved as the compiler evolves. Others, the programmer needs to watch out for. Let&amp;rsquo;s look at some of the most common ones. Some of the issues mentioned here aren&amp;rsquo;t exclusive to Go, but rather the result of bad code design that I&amp;rsquo;ve run into many times and that&amp;rsquo;s worth mentioning.&lt;/p></description></item><item><title>Variable Shadowing in Golang</title><link>https://crg.eti.br/pub/golang-shadow-variaveis/</link><pubDate>Sat, 15 Feb 2020 20:12:16 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/golang-shadow-variaveis/</guid><description>&lt;p>Go is an easy language to work with, and it helps you avoid a lot of common mistakes.&lt;/p>
&lt;p>But one mistake that&amp;rsquo;s easy to make in Go, and that the compiler still doesn&amp;rsquo;t warn you about, is variable shadowing.&lt;/p>
&lt;p>Shadowing happens when you declare a variable in one block and then declare it again, with the same name, in a nested block.&lt;/p>
&lt;p>You then change the value of the variable believing you&amp;rsquo;re updating the one from the outer block, but you&amp;rsquo;re actually only changing the variable in the current block.&lt;/p></description></item><item><title>First steps with assembly</title><link>https://crg.eti.br/pub/primeiros-passos-com-assembly/</link><pubDate>Sat, 08 Feb 2020 20:12:16 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/primeiros-passos-com-assembly/</guid><description>&lt;p>Every Thursday, a group of programmers and I get together to talk about Go in the &lt;a href="https://github.com/crgimenes/grupo-estudos-golang">Go Study Group&lt;/a>. We should probably rename it &lt;em>Technology Study Group&lt;/em>, since we end up discussing pretty much everything.&lt;/p>
&lt;p>One topic that keeps coming back is assembly programming. We&amp;rsquo;ve talked several times about putting together demos and toy programs loaded from the boot sector, known as &amp;ldquo;boot sector games.&amp;rdquo;&lt;/p>
&lt;p>Besides being fun, it&amp;rsquo;s a good way to teach how a computer works internally. Concepts like access speed, Lx cache, and others stay abstract in high-level languages.&lt;/p></description></item><item><title>Web Scraping with Golang</title><link>https://crg.eti.br/pub/web-scraping-com-golang/</link><pubDate>Mon, 23 Sep 2019 08:16:28 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/web-scraping-com-golang/</guid><description>&lt;p>I recently needed to extract some information from a website. My plan was simple: find the URL the search form pointed to, make the request directly from my program, then use the &lt;a href="https://github.com/PuerkitoBio/goquery">goquery&lt;/a> package to parse the results and pull out the data I wanted.&lt;/p>
&lt;p>Of course it wasn&amp;rsquo;t that easy. The site I wanted to crawl was full of JavaScript that interfered with the form, with the cookies, and with basically everything.&lt;/p></description></item><item><title>A Small 8086 CPU Emulator</title><link>https://crg.eti.br/pub/assembly-emulador-8086/</link><pubDate>Tue, 16 Jul 2019 08:16:28 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/assembly-emulador-8086/</guid><description>&lt;h2 id="8086-emulator-written-in-c">8086 Emulator Written in C&lt;/h2>
&lt;p>The first thing to make clear is that this is not a complete &lt;a href="https://en.wikipedia.org/wiki/Emulator">emulator&lt;/a>. The goal is only to interpret a hello world. Of course, you can take this skeleton and expand it into a full emulator.&lt;/p>
&lt;p>I was bored waiting for my friends to show up at &lt;a href="https://brasil.campus-party.org">Campus Party&lt;/a> 2016. I found the table set aside for the &lt;a href="https://en.wikipedia.org/wiki/Hackerspace">hackerspace&lt;/a> crowd and sat there waiting, but since there were no talks at that hour and nothing else I wanted to attend, I needed something to kill time.&lt;/p></description></item><item><title>Home Office, My Experience Working from Home</title><link>https://crg.eti.br/pub/home-office/</link><pubDate>Tue, 09 Jul 2019 20:12:16 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/home-office/</guid><description>&lt;p>Here I&amp;rsquo;ll go over a few things from my experience working from home, along with some tips on how I solved the common problems that anyone who wants to work in tech away from the office will run into.&lt;/p>
&lt;p>I&amp;rsquo;m a veteran when it comes to remote work. I started in the late 90s, back when I worked at a company with a bold, modern management style, especially for Brazil at the time. I was a young programmer with a lot still to learn.&lt;/p></description></item><item><title>BASIC Is Still Alive and Kicking</title><link>https://crg.eti.br/pub/basic-ainda-esta-vivo/</link><pubDate>Mon, 08 Jul 2019 20:12:16 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/basic-ainda-esta-vivo/</guid><description>&lt;p>While researching BASIC implementations, I found some interesting things. It&amp;rsquo;s amazing that a language this old, and with this many problems, still exists. You can even find commercial compilers still under active development for it.&lt;/p>
&lt;p>Yes, even though I&amp;rsquo;m a fan and love playing with BASIC for the nostalgia and the fun, there&amp;rsquo;s no denying that BASIC causes more problems than it solves. (In my opinion)&lt;/p>
&lt;p>Of course, an extremely simple language made sense when BASIC was born, in 1964. Machines had few resources, and the goal was a language for beginners. BASIC stands for &lt;a href="https://en.wikipedia.org/wiki/BASIC">Beginner&amp;rsquo;s All-Purpose Symbolic Instruction Code&lt;/a>&lt;/p></description></item><item><title>A Tricky Bug with Interfaces and Switch Cases in Go</title><link>https://crg.eti.br/pub/erro-na-ordem-do-switch/</link><pubDate>Sun, 24 Feb 2019 06:45:14 +0000</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/erro-na-ordem-do-switch/</guid><description>&lt;p>Watch the video about this bug on the &lt;a href="https://www.youtube.com/watch?v=v3h024EtxCU">Golang Study Group&lt;/a> channel (in Portuguese).&lt;/p>
&lt;p>Golang is an easy language to program in, and it has few traps for the programmer. Most things that can go wrong are caught by the compiler or by one of the many static analysis tools that help keep our code &lt;em>almost&lt;/em> bug free.&lt;/p>
&lt;p>But there are situations where even those tools have a hard time warning us, because there is no way to know what the programmer expected the program to do. This usually happens when you use the more entertaining features of the language, such as &lt;em>switch&lt;/em>, &lt;em>interfaces&lt;/em>, &lt;em>channels&lt;/em>, and &lt;em>goroutines&lt;/em>.&lt;/p></description></item><item><title>Unit Test Coverage in Go</title><link>https://crg.eti.br/pub/cobertura-de-testes/</link><pubDate>Wed, 13 Feb 2019 06:45:14 +0000</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/cobertura-de-testes/</guid><description>&lt;p>Unit tests are incredibly important, even for a compiled language like Golang.&lt;/p>
&lt;p>Fortunately, most programming languages today have a good variety of unit testing tools. Go ships with some surprising ones, not just for running tests but also for analyzing code to find coverage gaps.&lt;/p>
&lt;p>A quick, visual way to analyze test coverage is to write a script around &lt;code>go tool cover&lt;/code> and load it in &lt;code>zsh&lt;/code> or &lt;code>bash&lt;/code>, which makes inspecting the code very simple.&lt;/p></description></item><item><title>A Quine Implemented in Golang</title><link>https://crg.eti.br/pub/quine-em-golang/</link><pubDate>Tue, 12 Feb 2019 06:45:14 +0000</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/quine-em-golang/</guid><description>&lt;h2 id="printing-your-own-source-code">Printing your own source code&lt;/h2>
&lt;p>A quine is a program that prints its own source code to standard output. The name is a tribute to the mathematician and philosopher &lt;a href="https://en.wikipedia.org/wiki/Willard_Van_Orman_Quine">Willard Van Orman Quine&lt;/a>.&lt;/p>
&lt;p>There are &lt;a href="https://en.wikipedia.org/wiki/Quine_%28computing%29">quine&lt;/a> examples written in many programming languages. Writing your own version is an interesting exercise and a nice challenge.&lt;/p>
&lt;p>Keep in mind that the rule forbids simply opening your own source file and printing it — that would be cheating. Your code has to generate a copy of itself on standard output without reading it from anywhere.&lt;/p></description></item><item><title>PostgreSQL over SSL with Golang</title><link>https://crg.eti.br/pub/postgresql-ssl-golang/</link><pubDate>Fri, 04 Jan 2019 06:45:14 +0000</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/postgresql-ssl-golang/</guid><description>&lt;h2 id="creating-the-certificate">Creating the certificate&lt;/h2>
&lt;p>First, let&amp;rsquo;s create a test certificate. Of course, in production you should use a certificate issued by a recognized certificate authority.&lt;/p>
&lt;p>The command below creates two files, &lt;code>server.crt&lt;/code> and &lt;code>server.key&lt;/code>, which we will use to configure &lt;a href="https://www.postgresql.org">PostgreSQL&lt;/a>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>openssl req -new -x509 -days &lt;span style="color:#0550ae">365&lt;/span> -nodes -text -out server.crt &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> -keyout server.key -subj &lt;span style="color:#0a3069">&amp;#34;/CN=example.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="configuring-postgresql">Configuring PostgreSQL&lt;/h2>
&lt;p>Edit the postgresql.conf file to enable the SSL key.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>ssl = on
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ssl_cert_file = &amp;#39;server.crt&amp;#39;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ssl_key_file = &amp;#39;server.key&amp;#39;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Restart the service and test the connection with the following command:&lt;/p></description></item><item><title>Unix Domain Sockets with Golang</title><link>https://crg.eti.br/pub/unix-domain-socket-golang/</link><pubDate>Thu, 06 Dec 2018 06:45:14 +0000</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/unix-domain-socket-golang/</guid><description>&lt;ul>
&lt;li>&lt;em>Unix Domain Sockets&lt;/em> or &lt;em>&lt;a href="https://en.wikipedia.org/wiki/Inter-process_communication">IPC&lt;/a> Sockets&lt;/em>&lt;/li>
&lt;/ul>
&lt;p>&lt;em>Unix Domain Sockets&lt;/em> are a practical and secure way to exchange information between processes. This form of &lt;em>IPC&lt;/em> (Inter-process communication) uses a file as the address instead of an IP and a port, as network communication does.&lt;/p>
&lt;p>Keep in mind that the server manages the file. If the file does not exist, the server creates it automatically. If the file already exists, you get an error such as &amp;ldquo;bind: address already in use&amp;rdquo;, meaning the server cannot reuse the existing file. So it is good practice to shut the server down gracefully, closing and deleting the file before the server exits. Depending on the system, it may also be worth checking whether the file exists and deleting it before starting the server.&lt;/p></description></item><item><title>A JSON Lint in Golang</title><link>https://crg.eti.br/pub/json-lint-golang/</link><pubDate>Fri, 30 Nov 2018 06:45:14 +0000</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/json-lint-golang/</guid><description>&lt;p>Watch the video about this file &lt;a href="https://www.youtube.com/watch?v=VXVZE5SYMiM">here&lt;/a>.&lt;/p>
&lt;h2 id="a-json-lint-in-golang">A JSON Lint in Golang&lt;/h2>
&lt;p>This is a small command line utility to validate and format JSON that can also be used as a package. The original idea was to write a parser to validate the JSON, but that turned out to be unnecessary: Golang itself gives us everything we need in the error, including the offset where it happened. From there it was simple to display errors in a more complete way, with an arrow pointing at exactly where the problem is.&lt;/p></description></item><item><title>Passing Data Between HTTP Middleware Using Context in Golang</title><link>https://crg.eti.br/pub/middleware-em-golang/</link><pubDate>Fri, 09 Nov 2018 06:45:14 +0000</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/middleware-em-golang/</guid><description>&lt;p>Watch the video for this article &lt;a href="https://www.youtube.com/watch?v=Xyj-dQvfvq0">here&lt;/a>.&lt;/p>
&lt;h2 id="passing-data-between-middleware">Passing data between middleware&lt;/h2>
&lt;p>We have already seen &lt;a href="https://www.youtube.com/watch?v=aQGRh7ECgwg">how HTTP middleware works&lt;/a>, so now let&amp;rsquo;s look at how to pass information from one middleware to the next. This is used, for example, to hand a user&amp;rsquo;s credentials to the next middleware, or any other information collected in one middleware that you want to forward.&lt;/p>
&lt;p>First, let&amp;rsquo;s write an example that shows as clearly as possible when the middleware run. This matters a lot, because misunderstanding the execution order is an incredible source of bugs. In the example below we print a message to the terminal every time a middleware is pushed and popped. And it&amp;rsquo;s worth stressing: this happens in the same order in which they were registered.&lt;/p></description></item><item><title>How to Write HTTP Middleware in Golang, Both with Negroni and with the Standard Library</title><link>https://crg.eti.br/pub/middleware-usando-negroni/</link><pubDate>Fri, 02 Nov 2018 06:45:14 +0000</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/middleware-usando-negroni/</guid><description>&lt;p>You can watch the video version of this article &lt;a href="https://www.youtube.com/watch?v=aQGRh7ECgwg">here&lt;/a>.&lt;/p>
&lt;p>HTTP &lt;a href="https://en.wikipedia.org/wiki/Middleware">middleware&lt;/a> is very useful for avoiding duplicated code when your application has several endpoints — for example, when you want to make sure the user&amp;rsquo;s credentials have been verified, or that the content has been compressed, and so on.&lt;/p>
&lt;p>The most important thing to keep in mind is that each middleware runs in the order it was registered. So you can have a middleware responsible for setting up the environment, such as opening the database or preparing session handling, that runs before the middleware validating the user&amp;rsquo;s credentials.&lt;/p></description></item><item><title>Using goto and labels in Go</title><link>https://crg.eti.br/pub/goto-label-em-golang/</link><pubDate>Fri, 26 Oct 2018 06:45:14 +0000</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/goto-label-em-golang/</guid><description>&lt;p>The &lt;em>goto&lt;/em> statement has a bad reputation. Back in the BASIC days programmers did not have many options, so they abused &lt;em>goto&lt;/em> and wrote confusing code. Modern languages like Go use goto with judgment and improve code clarity.&lt;/p>
&lt;p>Go lets the &lt;em>break&lt;/em> and &lt;em>continue&lt;/em> statements use labels. Use labels to break out of nested loops or to continue a specific loop. Using &lt;em>break&lt;/em> or &lt;em>continue&lt;/em> with &lt;em>labels&lt;/em> is equivalent to using goto.&lt;/p></description></item><item><title>An Extremely Fast Messaging System with NATS and Golang</title><link>https://crg.eti.br/pub/mensageria-com-nats-e-golang/</link><pubDate>Fri, 19 Oct 2018 06:45:14 +0000</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/mensageria-com-nats-e-golang/</guid><description>&lt;p>Watch the video for this article &lt;a href="https://www.youtube.com/watch?v=NBi0r7QOJSs">here&lt;/a>.&lt;/p>
&lt;h2 id="messaging-with-nats">Messaging with NATS&lt;/h2>
&lt;p>If you need several systems talking to each other with speed and simplicity, &lt;a href="https://nats.io">NATS&lt;/a> is a great help. One of its most interesting traits is its incredible speed, and its simple protocol is easy to implement, so NATS shows up everywhere from IoT — there are client libraries even for Arduino — to communication between much larger services. It is also widely used in mobile applications for the same reason: a simple, fast protocol. It is a very interesting alternative to &lt;a href="https://mqtt.org">MQTT&lt;/a>, and it is implemented in Go. :D&lt;/p></description></item><item><title>Protocol Buffers</title><link>https://crg.eti.br/pub/protobuf-com-golang/</link><pubDate>Thu, 20 Sep 2018 08:19:09 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/protobuf-com-golang/</guid><description>&lt;p>Watch the video for this article &lt;a href="https://www.youtube.com/watch?v=XzSgREcg_sU">here&lt;/a>.&lt;/p>
&lt;p>This is the first in a series of quick tutorials where I plan to cover &lt;a href="https://grpc.io">gRPC&lt;/a> and various aspects of it, such as testing, TLS, best practices, and much more.&lt;/p>
&lt;p>To get started with gRPC we need to go all the way down to the foundation, so let&amp;rsquo;s talk about &lt;a href="https://developers.google.com/protocol-buffers">Protocol Buffers&lt;/a> first.&lt;/p>
&lt;p>Protocol Buffers is a simple, language-agnostic way to define a data structure. Think XML, but better, simpler, and faster — much faster.&lt;/p></description></item><item><title>ssh - Using access keys</title><link>https://crg.eti.br/pub/ssh-usando-chave/</link><pubDate>Sun, 09 Sep 2018 08:19:09 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/ssh-usando-chave/</guid><description>&lt;p>Watch the video for this article &lt;a href="https://www.youtube.com/watch?v=f-4R_PNEFT4">here&lt;/a>.&lt;/p>
&lt;p>Accessing servers over SSH with a public/private key pair is safer and more convenient — safer above all — and it also makes automating tasks much easier.&lt;/p>
&lt;h2 id="creating-the-keys">Creating the keys&lt;/h2>
&lt;p>First, generate the keys with the following command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>mkdir ~/.ssh
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ssh-keygen
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You only need to do this once on the client machine, and a key pair will be generated. You can choose the file name, which defaults to &lt;code>id_rsa&lt;/code> for the private key and &lt;code>id_rsa.pub&lt;/code> for the public key.&lt;/p></description></item><item><title>JSON, Writing Your Own Marshal and Unmarshal</title><link>https://crg.eti.br/pub/json-parser/</link><pubDate>Thu, 06 Sep 2018 08:19:09 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/json-parser/</guid><description>&lt;p>Watch the video for this article &lt;a href="https://www.youtube.com/watch?v=ALlzgQfXVFo">here&lt;/a>.&lt;/p>
&lt;p>Postgres&amp;rsquo;s default date format is incompatible with Go&amp;rsquo;s default format, and our system uses JSON heavily to both send and receive information from the database.&lt;/p>
&lt;p>Having to remember to parse the date into the correct format every single time simply isn&amp;rsquo;t practical. It&amp;rsquo;s much better to teach Go how to handle dates and times in good old ISO 8601.&lt;/p>
&lt;p>By the way, I highly recommend always using ISO 8601 UTC for everything in the backend, and only switching to the local format and timezone when displaying it to the user. But that&amp;rsquo;s a story for another day.&lt;/p></description></item><item><title>Interfaces as contracts</title><link>https://crg.eti.br/pub/interface-contrato/</link><pubDate>Thu, 30 Aug 2018 20:05:18 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/interface-contrato/</guid><description>&lt;p>Watch the video for this article &lt;a href="https://www.youtube.com/watch?v=ck9rGF0tfRE">here&lt;/a>.&lt;/p>
&lt;p>We covered this same topic in the example list of our study group on interfaces, but that was back in the distant year of 2016, so let&amp;rsquo;s build a new example showing how to use an interface as a contract. The contract lets you pass different types to a function, or accept different types through an interface, as long as they implement it — in other words, as long as they implement the functions described in the interface.&lt;/p></description></item><item><title>Using a VPN on macOS</title><link>https://crg.eti.br/pub/proton-vpm/</link><pubDate>Sat, 25 Aug 2018 20:05:18 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/proton-vpm/</guid><description>&lt;p>Like any tool, a &lt;a href="https://en.wikipedia.org/wiki/Virtual_private_network">VPN&lt;/a> is only effective if you know exactly which problem you want to solve with it. Some people want to keep their internet traffic anonymous, others want to protect their data, and so on. My own use is very specific: some internet providers are blocking important ports I need to reach certain services. For example, a well-known provider here in São Paulo is blocking TCP port 22, the one we use for SSH. Note that this is not the provider blocking incoming connections, which was already common, but outgoing ones — meaning that using any service that depends on SSH, like &lt;a href="https://github.com/crgimenes">GitHub&lt;/a>, or reaching a machine hosted on Google Cloud Platform&amp;rsquo;s Compute Engine becomes impossible.&lt;/p></description></item><item><title>The Empty Interface</title><link>https://crg.eti.br/pub/interface-vazia/</link><pubDate>Thu, 23 Aug 2018 20:05:18 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/interface-vazia/</guid><description>&lt;p>Watch the video for this article &lt;a href="https://www.youtube.com/watch?v=yBTzaVwqvng">here&lt;/a>.&lt;/p>
&lt;p>The empty interface is a type that accepts anything. You can pass whatever you want as a function parameter or store it in a variable of type &lt;code>interface{}&lt;/code>.&lt;/p>
&lt;p>At first glance this looks convenient, but when we use &lt;code>interface{}&lt;/code> we throw away the type validation done at compile time and lose one of the great advantages of a compiled language with strong, static typing.&lt;/p></description></item><item><title>JSON Tips and Tricks</title><link>https://crg.eti.br/pub/json-golang/</link><pubDate>Thu, 16 Aug 2018 20:05:18 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/json-golang/</guid><description>&lt;p>Watch the video for this article &lt;a href="https://www.youtube.com/watch?v=0PJ1YqO3wjI">here&lt;/a>.&lt;/p>
&lt;h2 id="converting-and-validating-json">Converting and validating JSON&lt;/h2>
&lt;p>It&amp;rsquo;s always good to check whether the JSON is valid first. That saves you debugging time chasing a problem that isn&amp;rsquo;t in your code. A good online tool for this is &lt;a href="https://jsonlint.com">JSONLint&lt;/a>.&lt;/p>
&lt;p>Another great online tool is &lt;a href="https://mholt.github.io/json-to-go">JSON-to-Go&lt;/a>, which converts JSON files into Go structs. It won&amp;rsquo;t factor repeated parts into sub-structs, but it helps a lot, especially when the structure is large and complex.&lt;/p></description></item><item><title>MS-DOS, APM with C and Assembly</title><link>https://crg.eti.br/pub/apm-msdos-assembly/</link><pubDate>Sun, 05 Aug 2018 20:05:18 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/apm-msdos-assembly/</guid><description>&lt;p>Watch the video of this article &lt;a href="https://www.youtube.com/watch?v=GTIIId3enis">here&lt;/a>.&lt;/p>
&lt;p>For retrocomputing fun, I use &lt;a href="https://www.virtualbox.org">VirtualBox&lt;/a> with &lt;a href="https://en.wikipedia.org/wiki/MS-DOS">MS-DOS 6.22&lt;/a> and &lt;a href="https://www.dosbox.com">DOSBox&lt;/a>. Both work very well, but the screen looks a bit better in VirtualBox, and DOSBox is faster and easier for developing and switching quickly between systems. So I use both.&lt;/p>
&lt;p>In DOSBox, you can close the emulator by typing the &lt;code>exit&lt;/code> command. That closes a command interpreter session and, if it is the last one, closes DOSBox itself. It is convenient because you do not need the mouse and it behaves more like a terminal.&lt;/p></description></item><item><title>Accessing Dropbox with Golang</title><link>https://crg.eti.br/pub/dropbox-com-golang/</link><pubDate>Thu, 02 Aug 2018 20:05:18 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/dropbox-com-golang/</guid><description>&lt;p>I needed a Golang package to talk to Dropbox and perform a few basic operations — listing files, uploading, and downloading. For that I used &lt;a href="https://github.com/dropbox/dropbox-sdk-go-unofficial">dropbox-sdk-go-unofficial&lt;/a>.&lt;/p>
&lt;h2 id="connecting-to-dropbox">Connecting to Dropbox&lt;/h2>
&lt;p>To connect to Dropbox you need access credentials. The easiest way is to create a token: go to &lt;a href="https://www.dropbox.com/developers/apps">Dropbox developers apps&lt;/a>, create an application, and then generate the token from the application&amp;rsquo;s panel.&lt;/p>
&lt;h2 id="configuring-the-system">Configuring the system&lt;/h2>
&lt;p>Every function needs the configuration with the access credentials and other useful parameters, such as the log level. So we create a function that returns an instance of the config struct.&lt;/p></description></item><item><title>Editing Command Lines in the Terminal</title><link>https://crg.eti.br/pub/comandos-longos-no-terminal/</link><pubDate>Sun, 08 Jul 2018 06:45:14 +0000</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/comandos-longos-no-terminal/</guid><description>&lt;p>I use the terminal a lot. It is amazing how the good old &lt;em>command line interface&lt;/em> &lt;code>cli&lt;/code> is still relevant, and still simply the fastest way to command a computer despite so many years of progress in computing.&lt;/p>
&lt;p>We just haven&amp;rsquo;t found a better way to enter commands yet. Over time, though, those commands have grown into what are practically small programs, sometimes several lines long, and sometimes containing things that are hard to edit, like regular expressions.&lt;/p></description></item><item><title>Static Compilation with Golang</title><link>https://crg.eti.br/pub/compilacao-estatica-com-golang/</link><pubDate>Sat, 02 Dec 2017 16:57:41 -0200</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/compilacao-estatica-com-golang/</guid><description>&lt;h2 id="building-monolithic-executables">Building monolithic executables&lt;/h2>
&lt;p>Watch the video for this article &lt;a href="https://www.youtube.com/watch?v=kdPWsCTREY8">here&lt;/a>.&lt;/p>
&lt;p>Golang already does a good job of statically compiling almost everything, but depending on your code you may need a few extra flags to make sure your executable is completely free of dependencies.&lt;/p>
&lt;p>The first step is to build your project and then inspect the binary to see whether it has any dependencies.&lt;/p>
&lt;p>On macOS, use the &lt;code>otool&lt;/code> utility (object file displaying tool) with the &lt;code>-L&lt;/code> flag (which lists the &lt;em>shared libraries&lt;/em> in use), like this:&lt;/p></description></item><item><title>Accessing the Serial Port</title><link>https://crg.eti.br/pub/formas-que-uso-para-acessar-porta-serial/</link><pubDate>Sat, 30 Sep 2017 21:22:29 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/formas-que-uso-para-acessar-porta-serial/</guid><description>&lt;p>Watch the video for this article &lt;a href="https://www.youtube.com/watch?v=4_TqPdyEQVM">here&lt;/a>.&lt;/p>
&lt;p>To me, one of the most interesting things is that the developers deliberately left out some features that screen has, such as telnet and serial port support. They did it because they believe in the &lt;a href="https://en.wikipedia.org/wiki/Unix">UNIX&lt;/a> philosophy of doing one thing and doing it well. In my opinion, they are absolutely right.&lt;/p>
&lt;h2 id="a-few-ways-to-access-the-serial-port">A few ways to access the serial port&lt;/h2>
&lt;p>No matter which method you pick to open the serial port, remember that it is meant to be accessed by only one program at a time. For another program to use the same port, the first one has to close it. This happens a lot when you forget an &lt;a href="https://www.arduino.cc">Arduino&lt;/a> serial terminal session open.&lt;/p></description></item><item><title>A horror story for programmers</title><link>https://crg.eti.br/pub/um-conto-de-terror-para-programadores/</link><pubDate>Wed, 26 Jul 2017 10:56:00 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/um-conto-de-terror-para-programadores/</guid><description>&lt;p>Many years ago there was a very famous Linux &lt;a href="https://en.wikipedia.org/wiki/Electronic_mailing_list">mailing list&lt;/a> where everybody hung out. But those were the early days and things were nowhere near as robust as they are today. Mailing lists were still the main way to exchange information because nobody had a 24/7 connection like we do now: you dialed in, downloaded your email, read everything offline, wrote your replies, dialed in again and sent them. Very rough around the edges, but it worked.&lt;/p></description></item><item><title>Golang: Playing with Bits</title><link>https://crg.eti.br/pub/go-brincando-com-bits/</link><pubDate>Mon, 03 Apr 2017 18:39:50 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/go-brincando-com-bits/</guid><description>&lt;h2 id="playing-with-bits">Playing with bits&lt;/h2>
&lt;p>The idea is to manipulate the CGA color palette, which stores colors in a single byte. This may look complicated, but it is actually very simple: we only need to learn a handful of operations to manipulate bits.&lt;/p>
&lt;p>Before we start, let&amp;rsquo;s agree on the following: when I talk about the upper or high part of a set of bits, I mean the leftmost bits, and when I talk about the lower or low part, I mean the rightmost bits. It is not always like this, but for the purposes of this text that is how it works — this is what we call &lt;a href="https://en.wikipedia.org/wiki/Endianness">lite-endian&lt;/a>&lt;/p></description></item><item><title>Golang defer tips</title><link>https://crg.eti.br/pub/dicas-de-go-defer/</link><pubDate>Fri, 24 Mar 2017 20:12:16 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/dicas-de-go-defer/</guid><description>&lt;p>Using &lt;a href="https://blog.golang.org/defer-panic-and-recover">defer&lt;/a> to postpone a command until the function returns, no matter how it returns, is an excellent idea. Imagine a function with several return points, either for errors or for a successful finish. Managing the closing of files, connections, mutexes, and other resources at each return becomes tedious and unsafe. You may forget to close a resource on some return path, and that can cause serious problems.&lt;/p>
&lt;p>However, using &lt;code>defer&lt;/code> has a cost. The runtime pushes the deferred command onto a stack, and deferring it is a few nanoseconds slower than a direct call. That is usually not a problem day to day, but if you need to squeeze the most performance out of your code, it may be worth considering.&lt;/p></description></item><item><title>Assembly, assembler, and machine language</title><link>https://crg.eti.br/pub/assembly-assembler-e-linguagem-de-maquina/</link><pubDate>Sun, 11 Sep 2016 08:16:28 -0300</pubDate><author>crg@crg.eti.br (Cesar Gimenes)</author><guid>https://crg.eti.br/pub/assembly-assembler-e-linguagem-de-maquina/</guid><description>&lt;h2 id="they-are-different-things">They Are Different Things&lt;/h2>
&lt;p>There are three different but related concepts that people often confuse. Let&amp;rsquo;s clarify each one.&lt;/p>
&lt;h3 id="assembly">Assembly&lt;/h3>
&lt;p>Assembly is a programming language made up of simple mnemonics. It directly corresponds to the instructions of the platform you’re using. When writing Assembly code, you know exactly what the processor is doing and gain access to resources that might not be available in higher-level languages. We can call Assembly a low-level language, meaning it’s closer to the hardware.&lt;/p></description></item></channel></rss>