<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>vladkens.cc</title>
    <subtitle>my tech blog</subtitle>
    <link rel="self" type="application/atom+xml" href="https://vladkens.cc/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://vladkens.cc"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2025-12-31T00:00:00+00:00</updated>
    <id>https://vladkens.cc/atom.xml</id>
    <entry xml:lang="en">
        <title>My 2025 Summary</title>
        <published>2025-12-31T00:00:00+00:00</published>
        <updated>2025-12-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/2025-summary/"/>
        <id>https://vladkens.cc/2025-summary/</id>
        
        <content type="html" xml:base="https://vladkens.cc/2025-summary/">&lt;p&gt;&lt;img src=&quot;&#x2F;20251231.webp&quot; alt=&quot;post cover image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Another year is coming to an end, and following my &lt;a href=&quot;&#x2F;2024-in-review&#x2F;&quot;&gt;new tradition&lt;&#x2F;a&gt;, I would like to sum up some results in writing. Overall, the year felt rather passive for me. I don’t remember planning any big things, but still, previous years were more active for me in terms of creativity and beyond (open source, learning new skills, and so on).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;open-source&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#open-source&quot; aria-label=&quot;Anchor link for: open-source&quot;&gt;Open Source&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This year, I didn’t release any new open-source projects, although I had some work in progress. I’m still maintaining my older projects little by little, but also without much enthusiasm (for some of them, this was the main idea from the start — stability).&lt;&#x2F;p&gt;
&lt;p&gt;More details about the main projects:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;twscrape&quot;&gt;twscrape&lt;&#x2F;a&gt; (my most popular project) — it constantly requires dealing with new obstacles introduced by X;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;apigen-ts&quot;&gt;apigen-ts&lt;&#x2F;a&gt; — in the near future, the codegen will need to be rewritten using templates, because &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;devblogs.microsoft.com&#x2F;typescript&#x2F;typescript-native-port&#x2F;&quot;&gt;TypeScript was rewritten in Go&lt;&#x2F;a&gt;, and there is a chance that AST primitives will be removed from the &lt;code&gt;typescript&lt;&#x2F;code&gt; package on npm. Also, for me personally, the project has become a bit less relevant due to using tRPC&#x2F;NextJS in my main stack, but for non-JS backends it is still a must-have;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&quot;&gt;macmon&lt;&#x2F;a&gt; — it is also quite difficult to maintain, because Apple releases new processors too often and in many different configurations, so it’s not always possible to get the required hardware for testing. I looked for online services that provide access to “bare metal” hardware via SSH for a limited time (a VPS-like model), but didn’t find anything suitable;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;ecloop&quot;&gt;ecloop&lt;&#x2F;a&gt; — I added SIMD optimizations for SHA-256 and RMD-160 to the library. I think this was my most interesting task this year. I wanted to play around with CUDA and even ordered a computer for that, but ended up not using it. As for crypto itself, I got into degen stuff (more on that later).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Public projects on GitHub — a total of 92 commits, 79 closed issues, 11 releases created, and more than 1k stars gained.&lt;&#x2F;p&gt;
&lt;p&gt;UPD: I remembered that at the end of 2024 &#x2F; beginning of 2025, I worked on &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;badges&quot;&gt;badges.ws&lt;&#x2F;a&gt; in Rust. It looked like a fairly simple task, but turned into several months of work and debugging various APIs. In general, I probably should have dropped the project earlier, but I didn’t and pushed it through to a release — at the cost of my motivation to start new projects. What conclusion to draw from this, I’m not sure.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;blog&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#blog&quot; aria-label=&quot;Anchor link for: blog&quot;&gt;Blog&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Overall, this year I wanted to write more posts, and I even have many drafts, but at some point I wanted to switch to a more convenient engine than &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zola&lt;&#x2F;a&gt; (which I currently use). However, I couldn’t find anything good and flexible enough.&lt;&#x2F;p&gt;
&lt;p&gt;Problems with Zola:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;a strange templating language that lacks some features, while issues remain open for years;&lt;&#x2F;li&gt;
&lt;li&gt;GPT tools don’t handle this templating system well — every time I need to make a change, it’s hard even to google how to do it;&lt;&#x2F;li&gt;
&lt;li&gt;lack of flexibility in page navigation and file organization (I can’t arrange blog files the way I want and have to follow the engine’s structure);&lt;&#x2F;li&gt;
&lt;li&gt;broken redirects in content — Zola doesn’t understand relative links in text (all links must be written relative to the site navigation), so it’s not convenient to write and work with the blog locally: linking between my own posts and being sure that all links are valid. Right now, I have to solve this with a separate script.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As an engine, I would like something that uses JSX as a templating language, has Tailwind CSS out of the box, doesn’t have Zola’s navigation and linking issues, and is a simple and stable solution. Overall, &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;astro.build&#x2F;&quot;&gt;Astro&lt;&#x2F;a&gt; fits this category, and I tried migrating the blog to it, but it also has a number of its own problems:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;duplicated logic and the difficulty of choosing between &lt;code&gt;.astro&lt;&#x2F;code&gt; and &lt;code&gt;.jsx&lt;&#x2F;code&gt; formats;&lt;&#x2F;li&gt;
&lt;li&gt;lack of proper MD&#x2F;MDX integration (any customization is done via CSS classes instead of properly overriding the rendering of Markdown tags with JSX components);&lt;&#x2F;li&gt;
&lt;li&gt;no built-in Atom feed generation (only RSS is supported), which means it has to be implemented manually.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Overall, I did a test migration of the blog to Astro, but never released it, because the solution felt too complex. A blog is something you might not touch for months, and when you finally do, you want to immediately understand how things work, rather than having to google or ask GPT for solutions.&lt;&#x2F;p&gt;
&lt;p&gt;I also considered NextJS as an option, since it can be configured to fit your needs, but there are big concerns about its stability. I really don’t want to read changelogs every few months just to understand their new vision and figure out what needs to be updated in something that already worked, just to keep it working the same way.&lt;&#x2F;p&gt;
&lt;p&gt;That turned into a lot of text about the blog. In short, I’d like to write more while being less distracted by technical problems. The ideal solution for me right now would be MD&#x2F;MDX with the ability to override elements. Maybe someone knows a good existing solution? (or maybe it’s an idea for a project on Bun)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;skills&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#skills&quot; aria-label=&quot;Anchor link for: skills&quot;&gt;Skills&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In previous years, I explored and practiced DevOps, Rust, Go, LLMs, NestJS&#x2F;NextJS, and other things, but this year felt neutral. I can’t quickly name anything new that I learned this year. Probably the main change in my work environment was the &lt;a href=&quot;&#x2F;from-iterm-to-wezterm&#x2F;&quot;&gt;switch from iTerm2 to WezTerm&lt;&#x2F;a&gt;. The reason was adding LLM features to the terminal and a &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=42579472&quot;&gt;security vulnerability&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, throughout the year it felt scary to update software. A lot of things are now being built with AI, and the quality of releases has become frankly weaker. For example:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;I’ve been using Chrome since 2009, and this year was the first time I saw rendering bugs, crashes, and similar issues;&lt;&#x2F;li&gt;
&lt;li&gt;Google Search was broken for several months, and they didn’t seem to care (if you type a query with a typo, Search suggests the correct version, you can click it and it appears in the search field, but if you then click into the field, it reverts back to the original typo — this might seem like a small issue to some, but it’s a very common use case for me);&lt;&#x2F;li&gt;
&lt;li&gt;on YouTube, for several days after releasing the new player, the volume couldn’t be increased above 60% via the UI: the slider just wouldn’t move. I don’t understand how something that wasn’t even properly tested in production could be released;&lt;&#x2F;li&gt;
&lt;li&gt;many similar small bugs that ruin the UX.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In short, something has gone wrong in the world of software development. That’s why updating feels risky — you never know how your workflow will break this time. My favorite app is &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.sublimemerge.com&#x2F;&quot;&gt;Sublime Merge&lt;&#x2F;a&gt;: updates there are purely cosmetic and happen only a couple of times a year.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;crypto-aka-degen&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#crypto-aka-degen&quot; aria-label=&quot;Anchor link for: crypto-aka-degen&quot;&gt;Crypto aka Degen&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This area deserves a separate mention. In January, I worked on a small project for bridging ERC-20 &#x2F; SPL tokens between the Ethereum and Solana networks. Around the same time, Trump released his &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=42749681&quot;&gt;Meme Coin&lt;&#x2F;a&gt;: those who were insiders or just fast made good money, while everyone else ended up at a loss. That got me interested in how crypto works in general — not the technical side, but the community itself.&lt;&#x2F;p&gt;
&lt;p&gt;As a result, I subscribed to various chats and other sources with related information (though it’s a huge stream, often full of noise). Later, I found the &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.doubletop.io&#x2F;&quot;&gt;DoubleTop community&lt;&#x2F;a&gt;, where I’m now a member and communicate regularly.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, during the second half of the year I was moderately active in crypto — trying different areas to understand how things work. So far, my experience is this: it is possible to make money in crypto, but it’s really difficult and requires a lot of time and attention. Losing money is much easier. There are no huge multipliers on deposits, but steady percentages are possible.&lt;&#x2F;p&gt;
&lt;p&gt;Cases I participated in:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;coinlist.co&#x2F;fleek&quot;&gt;Sale Fleek on CoinList&lt;&#x2F;a&gt; — rekt −70%, the team basically scammed;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;coinlist.co&#x2F;enso&quot;&gt;Sale Enso on CoinList&lt;&#x2F;a&gt; — good result, +70%;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;crypto.news&#x2F;plasma-raises-500m-in-oversubscribed-xpl-token-sale-for-stablecoin-focused-blockchain&#x2F;&quot;&gt;Sale Plasma&lt;&#x2F;a&gt; — x10 on allocation, but it was hard to get in, and funds were locked for 3 months;&lt;&#x2F;li&gt;
&lt;li&gt;Sale Pump.fun — x2 in 3 days, but as always, there were nuances. I was lucky to get part of the allocation through the website, while CEXs issued refunds;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;app.legion.cc&#x2F;leaderboard&#x2F;almanak&#x2F;overview&quot;&gt;Almanak on Legion&lt;&#x2F;a&gt; — rekt −50%. Overall, it was a decent project, but the team delayed the launch and went live in a bad market. I forgot that I participated in this sale and didn’t sell the tokens in time;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;app.paradex.trade&#x2F;r&#x2F;vladkens&quot;&gt;Farm Paradex&lt;&#x2F;a&gt; — x2 on spend. The project was expected to launch in summer, but the release was later postponed indefinitely. This was my first retrodrop-focused project, so my enthusiasm for farming other projects cooled down. In November–December, the Paradex team added an XP transfer option, which made it possible to sell points OTC, and I used that;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;app.lighter.xyz&#x2F;?referral=VLADKENS&quot;&gt;Farm Lighter&lt;&#x2F;a&gt; — a lot of multiples here. I earned most of my points from hedge positions and didn’t farm aggressively on purpose. Given how bad the market is right now, the project literally gave everyone a New Year’s gift;&lt;&#x2F;li&gt;
&lt;li&gt;Binance Alpha — simple daily activity that required generating trading volume on Binance. It brought about $300–400 per month per account, but it was hard to multi-account;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;buidlpad.com&#x2F;&quot;&gt;Sales on BuidlPad&lt;&#x2F;a&gt; — the platform provided stable returns for about half a year. It was easy to multi-account, but accounts were also often blocked. A lot of liquidity was required to participate, since allocations were small. On average, all sales ended up around x2 on spend;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.coindesk.com&#x2F;markets&#x2F;2025&#x2F;10&#x2F;12&#x2F;altcoins-cratered-in-oct-10-crypto-flash-crash-as-bitcoin-held-up-wiston-capital-says&quot;&gt;Flash crash on Oct 10&lt;&#x2F;a&gt; — the whole crypto market dropped hard within a couple of hours and still hasn’t returned to previous levels. I didn’t have any perp positions, so I got lucky there, but I did have USDT&#x2F;USDC loans backed by crypto assets that were liquidated;&lt;&#x2F;li&gt;
&lt;li&gt;Spot positions (bad market): BNB +30%, ETH +20%, SOL −20%, HYPE −40%.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Of course, there were more cases — I listed the main closed ones. In general, it is possible to make money in crypto, but it’s really hard and requires a systematic approach. The crypto market is alive only for a few months a year, when so many events happen that it’s impossible to participate in everything (not enough capital, energy, or time). For most of the year, nothing really happens — that’s when people go work at McDonald’s.&lt;&#x2F;p&gt;
&lt;p&gt;That quiet period is usually the time to farm retrodrops, but it’s genuinely difficult work: the results of your actions and money spent come only after 6–12 months, and psychologically that’s hard for me.&lt;&#x2F;p&gt;
&lt;p&gt;The current meta is Perp DEXes (Paradex &#x2F; Lighter &#x2F; Aster &#x2F; Extended &#x2F; Pacifica.fi &#x2F; Ethereal &#x2F; Trade.xyz &#x2F; etc.) and opinion markets (Polymarket &#x2F; Opinion &#x2F; Limitless &#x2F; etc.).&lt;&#x2F;p&gt;
&lt;p&gt;The hardest part of crypto for me is tracking balances and understanding whether I’m up or down overall (it’s basically real accounting work). Roughly speaking, I finished the year at about the same level I started, although at some points my deposit was up to +50%. It’s important to note that everything related to crypto should be done with proper risk control — I have a separate budget that I use only for experiments.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, this is a big topic, and I’ll probably need to talk about it separately.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;health&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#health&quot; aria-label=&quot;Anchor link for: health&quot;&gt;Health&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Still alive — and that’s good.&lt;&#x2F;p&gt;
&lt;p&gt;This year I &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;uid127&#x2F;status&#x2F;1941981050499965175&quot;&gt;quit smoking&lt;&#x2F;a&gt; — I’m very happy about it, I feel better, and I’ve reduced the risk of various cancers. Overall, quitting wasn’t that hard: I watched a few YouTube videos to understand what to expect and what kind of “tricks” my brain would use to convince me to smoke again. For the first three weeks or so, you constantly think about smoking, and then it fades. Most of this “thinking” isn’t about smoking itself, but about habits and routines — like taking a break, looking out the window, having a coffee, and going for a smoke. Now, from time to time, I get short five-minute urges in the form of flashbacks.&lt;&#x2F;p&gt;
&lt;p&gt;I also started doing regular stretching&#x2F;exercises — at least a couple of times a week (I track it in Sheets). Without this, I genuinely feel worse: it’s hard to work when your back hurts, for example. I periodically take body measurements, and probably the main change is my biceps: +2 cm.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;leisure&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#leisure&quot; aria-label=&quot;Anchor link for: leisure&quot;&gt;Leisure&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I bought an Xbox to relax by playing games (I had a PlayStation 4 in the past, so I wanted to try a different platform). I tried quite a lot of games via Game Pass — before that, I hadn’t played much for several years. From what I liked:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Clair Obscur: Expedition 33 — an obvious game of the year, 100% worth playing: the story, art, music, and combat are all excellent.&lt;&#x2F;li&gt;
&lt;li&gt;Mafia: Definitive Edition — a remake of a classic, slightly simplified. The racing mission still takes dozens of attempts — and that’s a good thing.&lt;&#x2F;li&gt;
&lt;li&gt;Indiana Jones and the Great Circle — a solid game. It was enjoyable to explore Rome and the Egyptian pyramids and solve local puzzles. The fistfights are also quite fun, and you don’t really want to use firearms.&lt;&#x2F;li&gt;
&lt;li&gt;Doom: The Dark Ages — the legendary demon-slaying series. I only played Doom 1 and Doom 3 before and skipped the entire modern lineup. I decided to start with The Dark Ages. Overall, the first half of the game is interesting: great locations, new weapons constantly unlocking, and so on. But the second half feels tedious — all locations turn into the same gray corridors. The robot titan missions were cool, though.&lt;&#x2F;li&gt;
&lt;li&gt;Assassin&#x27;s Creed Mirage — at first it felt like just another Assassin’s Creed, but the more I played, the better it got. I have warm memories of Baghdad. In my opinion, it’s one of the strongest games in the series. What’s nice is that it’s short. I played it before the &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.pcgamer.com&#x2F;games&#x2F;assassins-creed&#x2F;two-years-after-launch-assassins-creed-mirage-is-getting-surprise-free-dlc-adding-a-second-city-to-the-game&#x2F;&quot;&gt;recent DLC&lt;&#x2F;a&gt;; people say it’s even better now.&lt;&#x2F;li&gt;
&lt;li&gt;Escape from Duckov — a meme game in the extraction genre. I didn’t finish it because it’s quite long, but it’s worth trying to understand the genre. It’s addictive.&lt;&#x2F;li&gt;
&lt;li&gt;Lies of P — my first proper soulslike (before that, I only tried Sekiro, which was hell for me). I liked it: the bosses are manageable for a regular player, and there are many ways to beat them (shadow pulls, throwable jars with liquids). The story is simple and interesting, although the playtime feels a bit stretched toward the end.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Other media that stood out.&lt;&#x2F;p&gt;
&lt;p&gt;Movies &#x2F; TV shows: &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.imdb.com&#x2F;title&#x2F;tt1896747&#x2F;&quot;&gt;Fly Me to the Moon (2024)&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.imdb.com&#x2F;title&#x2F;tt0037323&#x2F;&quot;&gt;The Fighting Sullivans (1944)&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.imdb.com&#x2F;title&#x2F;tt0169547&#x2F;&quot;&gt;American Beauty (1999)&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.imdb.com&#x2F;title&#x2F;tt3402138&#x2F;&quot;&gt;The Naked Gun (2025)&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.imdb.com&#x2F;title&#x2F;tt0060522&#x2F;&quot;&gt;How to Steal a Million (1966)&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.imdb.com&#x2F;title&#x2F;tt7131622&#x2F;&quot;&gt;Once Upon a Time... in Hollywood (2019)&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.imdb.com&#x2F;title&#x2F;tt12300742&#x2F;&quot;&gt;Bugonia (2025)&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.imdb.com&#x2F;title&#x2F;tt1630029&#x2F;&quot;&gt;Аватар: Путь воды (2022)&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Music: Sabrina Carpenter, The Velvet Sundown (yes, AI slop), Alice in Chains.&lt;&#x2F;p&gt;
&lt;p&gt;Books: I didn’t read much; the most recent one was Ionesco’s &lt;em&gt;Rhinoceros&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Happy New Year to everyone! 🎉&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Optimizing RIPEMD-160 with SIMD</title>
        <published>2025-05-08T00:00:00+00:00</published>
        <updated>2025-05-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/rmd160-simd/"/>
        <id>https://vladkens.cc/rmd160-simd/</id>
        
        <content type="html" xml:base="https://vladkens.cc/rmd160-simd/">&lt;!-- # Optimizing RIPEMD-160 with SIMD --&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;20250508.png&quot; alt=&quot;post cover image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I have a hobby project – &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;ecloop&quot;&gt;ecloop&lt;&#x2F;a&gt; – a Bitcoin key &quot;calculator&quot; designed to find Bitcoin puzzles, verify brain wallets, and so on. The mathematical chances of finding a private key from a used address tend toward zero. I&#x27;m interested in this program as a collection of tricks involving the elliptic curve (secp256k1) and as a way to practice low-level programming (fast 256-bit arithmetic), so I continue to develop it from time to time.&lt;&#x2F;p&gt;
&lt;p&gt;To calculate a Bitcoin address from a private key, several operations need to be performed:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Calculate the point on the elliptic curve (public key): &lt;code&gt;P = G * PrivKey&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Compute SHA-256 from the compressed public key: &lt;code&gt;(P.y % 2 == 0 ? 0x02 : 0x03) + P.x&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Compute RIPEMD-160 from the resulting SHA-256 hash.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The result is the so-called &lt;code&gt;hash160&lt;&#x2F;code&gt;, which is then encoded into a Bitcoin address using either &lt;code&gt;base58&lt;&#x2F;code&gt; or &lt;code&gt;bech32&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;As slow as elliptic curve operations are, the slowest part of address generation is the RIPEMD-160 (RMD160) calculation. In fact, it takes about half of the total execution time (SHA-256 is hardware-accelerated on modern processors).&lt;&#x2F;p&gt;
&lt;p&gt;Almost all modern processors have SIMD support: AVX2 on amd64 and Neon on arm64. That&#x27;s why I decided it would be worthwhile to speed up RMD160 by implementing it using parallel calculations. Moreover, I had never written SIMD code before, so I was interested in trying it out.&lt;&#x2F;p&gt;
&lt;p&gt;My main computer is a MacBook with Apple Silicon (M-series chips). Initially, I wanted to implement RMD160 SIMD using SVE (256-bit &#x2F; 8-lane), but it turned out that Apple chips do not support SVE 🤦. (To clarify: the M2 chip implements the ARMv8.6 standard, while SVE was introduced in ARMv8.2 as an optional feature). So I had to use Neon (128-bit &#x2F; 4-lane). If that&#x27;s not the case and there is a way to run SVE instructions on M-series chips, I&#x27;d be happy to hear about it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-rmd160&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-is-rmd160&quot; aria-label=&quot;Anchor link for: what-is-rmd160&quot;&gt;What is RMD160?&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;RIPEMD-160 (RMD160) is a cryptographic hash function that produces a 160-bit hash from arbitrary data. It was developed as a secure alternative to earlier algorithms such as MD5 and SHA-1. RMD160 is widely used in blockchain technology, particularly in Bitcoin, where it is used to generate wallet addresses: the public key is first hashed using SHA-256, and then hashed again with RMD160 to improve security and reduce length.&lt;&#x2F;p&gt;
&lt;p&gt;The RMD160 algorithm consists of five rounds. Each round includes basic logical functions, cyclic shifts (ROTL), and addition. A distinctive feature of RMD160 is that each round is executed in two parallel branches: the main (left) branch and the parallel (right) branch. These two branches use different constants, word orders, and logic functions, and their results are later combined.&lt;&#x2F;p&gt;
&lt;p&gt;There is a &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;homes.esat.kuleuven.be&#x2F;~bosselae&#x2F;ripemd160&#x2F;ps&#x2F;AB-9601&#x2F;rmd160.h&quot;&gt;classic&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;homes.esat.kuleuven.be&#x2F;~bosselae&#x2F;ripemd160&#x2F;ps&#x2F;AB-9601&#x2F;rmd160.c&quot;&gt;C implementation&lt;&#x2F;a&gt; of RMD160 that uses a bunch of macros to define rounds, logical functions, and so on—but such code is hard to read. So I prefer the &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;cs.opensource.google&#x2F;go&#x2F;x&#x2F;crypto&#x2F;+&#x2F;refs&#x2F;tags&#x2F;v0.37.0:ripemd160&#x2F;ripemd160block.go&quot;&gt;Golang implementation&lt;&#x2F;a&gt;, which I previously ported to &lt;code&gt;ecloop&lt;&#x2F;code&gt;. I plan to continue the porting to Neon based on this codebase.&lt;&#x2F;p&gt;
&lt;p&gt;Stepping back a bit, SIMD instructions aren&#x27;t extremely complex, but they lack &quot;syntactic sugar&quot; — so instead of writing &lt;code&gt;a + b&lt;&#x2F;code&gt;, you need to write something like &lt;code&gt;vaddq_u32(a, b)&lt;&#x2F;code&gt;. There are special functions like this for every standard operation multiplied by the number of numeric types (u&#x2F;i 8&#x2F;16&#x2F;32&#x2F;64, f16&#x2F;32&#x2F;64).&lt;&#x2F;p&gt;
&lt;p&gt;RMD160 (like other hash functions) should not be too difficult to port to SIMD because their algorithms contain no branching. Essentially, the logic stays the same; it&#x27;s just a matter of replacing all operations with SIMD-specific instructions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;simple-neon-program&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#simple-neon-program&quot; aria-label=&quot;Anchor link for: simple-neon-program&quot;&gt;Simple Neon Program&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;To understand how to write using Neon, we should start with the simplest possible program, such as multiplying 42 × 2. Since SIMD involves parallel computations, its operations are applied to the entire vector at once, and the result should be the same across all parts of the vector. To verify this, the result can be printed to the console.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;arm_neon.h&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;stdint.h&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;stdio.h&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(uint32x4_t *&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;  uint32_t arr[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vst1q_u32&lt;&#x2F;span&gt;&lt;span&gt;(arr, *a); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; store 4x32-bit vector into a regular array
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;; i++) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%x%c&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, arr[i], i == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3 &lt;&#x2F;span&gt;&lt;span&gt;? &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; : &amp;#39; &amp;#39;);
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;  uint32_t a = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;42&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  uint32x4_t b = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;42&lt;&#x2F;span&gt;&lt;span&gt;); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; load u32 to all 4 lanes (42, 42, 42, 42)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; = &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, a);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;b); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; out: 2a = 2a 2a 2a 2a
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  a = a * &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  b = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vmulq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(b, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; multiply each lane by 2
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; = &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, a);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;b); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; out: 54 = 54 54 54 54
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In general, I think the concept of how SIMD calculations work is clear. From here on, &lt;code&gt;print_check&lt;&#x2F;code&gt; will be used frequently to check the correctness of the hashing algorithm.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;basic-functions-and-rotl&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#basic-functions-and-rotl&quot; aria-label=&quot;Anchor link for: basic-functions-and-rotl&quot;&gt;Basic Functions and ROTL&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The RMD160 calculation uses 5 basic functions and ROTL; everything else is a shuffling of data in a specific order. GPT has rewritten these macros, and I have verified that they are correct:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; original functions
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;OLD_F1&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) ((x) ^ (y) ^ (z))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;OLD_F2&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) (((x) &amp;amp; (y)) | (~(x) &amp;amp; (z)))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;OLD_F3&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) (((x) | ~(y)) ^ (z))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;OLD_F4&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) (((x) &amp;amp; (z)) | ((y) &amp;amp; ~(z)))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;OLD_F5&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) ((x) ^ ((y) | ~(z)))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;OLD_ROTL&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;n&lt;&#x2F;span&gt;&lt;span&gt;) (((x) &amp;lt;&amp;lt; (n)) | ((x) &amp;gt;&amp;gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;32 &lt;&#x2F;span&gt;&lt;span&gt;- (n))))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; simd functions
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;F1&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;veorq_u32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;veorq_u32&lt;&#x2F;span&gt;&lt;span&gt;(x, y), z)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;F2&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vorrq_u32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vandq_u32&lt;&#x2F;span&gt;&lt;span&gt;(x, y), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vandq_u32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vmvnq_u32&lt;&#x2F;span&gt;&lt;span&gt;(x), z))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;F3&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;veorq_u32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vorrq_u32&lt;&#x2F;span&gt;&lt;span&gt;(x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vmvnq_u32&lt;&#x2F;span&gt;&lt;span&gt;(y)), z)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;F4&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vorrq_u32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vandq_u32&lt;&#x2F;span&gt;&lt;span&gt;(x, z), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vandq_u32&lt;&#x2F;span&gt;&lt;span&gt;(y, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vmvnq_u32&lt;&#x2F;span&gt;&lt;span&gt;(z)))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;F5&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;veorq_u32&lt;&#x2F;span&gt;&lt;span&gt;(x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vorrq_u32&lt;&#x2F;span&gt;&lt;span&gt;(y, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vmvnq_u32&lt;&#x2F;span&gt;&lt;span&gt;(z)))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;ROTL&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;n&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vorrq_u32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vshlq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(x, n), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vshrq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;32 &lt;&#x2F;span&gt;&lt;span&gt;- (n)))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;char &lt;&#x2F;span&gt;&lt;span&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;l&lt;&#x2F;span&gt;&lt;span&gt;, uint32_t &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, uint32x4_t &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%08x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; = &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, l, c);
&lt;&#x2F;span&gt;&lt;span&gt;  uint32_t arr[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vst1q_u32&lt;&#x2F;span&gt;&lt;span&gt;(arr, a); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; store 4x32-bit vector into a regular array
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;; i++) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%08x%c&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, arr[i], i == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3 &lt;&#x2F;span&gt;&lt;span&gt;? &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; : &amp;#39; &amp;#39;);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; assert(arr[i] == c);
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;uint32_t a1, b1, c1;
&lt;&#x2F;span&gt;&lt;span&gt;uint32x4_t a2, b2, c2;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;a1 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x67452301&lt;&#x2F;span&gt;&lt;span&gt;, b1 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0xefcdab89&lt;&#x2F;span&gt;&lt;span&gt;, c1 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x98badcfe&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;a2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(a1), b2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(b1), c2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(c1); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; loading vectors
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; compare original and simd functions
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;F1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;OLD_F1&lt;&#x2F;span&gt;&lt;span&gt;(a1, b1, c1), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F1&lt;&#x2F;span&gt;&lt;span&gt;(a2, b2, c2));
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;F2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;OLD_F2&lt;&#x2F;span&gt;&lt;span&gt;(a1, b1, c1), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F2&lt;&#x2F;span&gt;&lt;span&gt;(a2, b2, c2));
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;F3&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;OLD_F3&lt;&#x2F;span&gt;&lt;span&gt;(a1, b1, c1), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F3&lt;&#x2F;span&gt;&lt;span&gt;(a2, b2, c2));
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;F4&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;OLD_F4&lt;&#x2F;span&gt;&lt;span&gt;(a1, b1, c1), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F4&lt;&#x2F;span&gt;&lt;span&gt;(a2, b2, c2));
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;F5&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;OLD_F5&lt;&#x2F;span&gt;&lt;span&gt;(a1, b1, c1), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F5&lt;&#x2F;span&gt;&lt;span&gt;(a2, b2, c2));
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;RL&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;OLD_ROTL&lt;&#x2F;span&gt;&lt;span&gt;(a1, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ROTL&lt;&#x2F;span&gt;&lt;span&gt;(a2, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;));
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; output:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; F1: 10325476 = 10325476 10325476 10325476 10325476
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; F2: ffffffff = ffffffff ffffffff ffffffff ffffffff
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; F3: efcdab89 = efcdab89 efcdab89 efcdab89 efcdab89
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; F4: 67452301 = 67452301 67452301 67452301 67452301
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; F5: 88888888 = 88888888 88888888 88888888 88888888
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; RL: 52301674 = 52301674 52301674 52301674 52301674
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;problem-with-porting-golang-implementation&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#problem-with-porting-golang-implementation&quot; aria-label=&quot;Anchor link for: problem-with-porting-golang-implementation&quot;&gt;Problem with Porting Golang Implementation&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The Golang implementation consists of 5 large loops, each performing 16 left and right rounds. Inside each operation, the input data is mixed at index &lt;code&gt;_n[i]&lt;&#x2F;code&gt;, and ROTL is performed at index &lt;code&gt;_r[i]&lt;&#x2F;code&gt;. The reference C implementation uses a series of consecutive macros, which makes it harder to read (in my opinion).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Golang implementation
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;static const&lt;&#x2F;span&gt;&lt;span&gt; u8 _n[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;80&lt;&#x2F;span&gt;&lt;span&gt;] = { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* ... *&#x2F; &lt;&#x2F;span&gt;&lt;span&gt;}; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Left DATA indexes
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;static const&lt;&#x2F;span&gt;&lt;span&gt; u8 _r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;80&lt;&#x2F;span&gt;&lt;span&gt;] = { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;* ... *&#x2F; &lt;&#x2F;span&gt;&lt;span&gt;}; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Left ROTL indexes
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; round 1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(; i &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;; ++i) {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; left branch
&lt;&#x2F;span&gt;&lt;span&gt;  alpha = a1 + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F1&lt;&#x2F;span&gt;&lt;span&gt;(b1, c1, d1) + x[_n[i]];
&lt;&#x2F;span&gt;&lt;span&gt;  alpha = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rotl32&lt;&#x2F;span&gt;&lt;span&gt;(alpha, _r[i]) + e1;
&lt;&#x2F;span&gt;&lt;span&gt;  beta = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rotl32&lt;&#x2F;span&gt;&lt;span&gt;(c1, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  a1 = e1, c1 = b1, e1 = d1, b1 = alpha, d1 = beta;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; right branch
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Reference C-implementation
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;F&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;)        ((x) ^ (y) ^ (z))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;FF&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;s&lt;&#x2F;span&gt;&lt;span&gt;)        {\
&lt;&#x2F;span&gt;&lt;span&gt;      (a) += &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F&lt;&#x2F;span&gt;&lt;span&gt;((b), (c), (d)) + (x);\
&lt;&#x2F;span&gt;&lt;span&gt;      (a) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ROL&lt;&#x2F;span&gt;&lt;span&gt;((a), (s)) + (e);\
&lt;&#x2F;span&gt;&lt;span&gt;      (c) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ROL&lt;&#x2F;span&gt;&lt;span&gt;((c), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;);\
&lt;&#x2F;span&gt;&lt;span&gt;   }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; round 1 - left branch
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;FF&lt;&#x2F;span&gt;&lt;span&gt;(aa, bb, cc, dd, ee, X[ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;FF&lt;&#x2F;span&gt;&lt;span&gt;(ee, aa, bb, cc, dd, X[ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;FF&lt;&#x2F;span&gt;&lt;span&gt;(bb, cc, dd, ee, aa, X[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;],  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;9&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;FF&lt;&#x2F;span&gt;&lt;span&gt;(aa, bb, cc, dd, ee, X[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;],  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In general, if we rewrite the code directly using Neon instructions, the compilation crashes with an error stating that &lt;code&gt;vshlq_n_u32&lt;&#x2F;code&gt; and &lt;code&gt;vshrq_n_u32&lt;&#x2F;code&gt; require a known rotation value (the second argument) at compile time. See:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Golang implementation (original)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;F1&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) ((x) ^ (y) ^ (z))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;rotl32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;n&lt;&#x2F;span&gt;&lt;span&gt;) (((x) &amp;lt;&amp;lt; (n)) | ((x) &amp;gt;&amp;gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;32 &lt;&#x2F;span&gt;&lt;span&gt;- (n))))
&lt;&#x2F;span&gt;&lt;span&gt;alpha = a1 + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F1&lt;&#x2F;span&gt;&lt;span&gt;(b1, c1, d1) + x[_n[i]];
&lt;&#x2F;span&gt;&lt;span&gt;alpha = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rotl32&lt;&#x2F;span&gt;&lt;span&gt;(alpha, _r[i]) + e1;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Golang implementation (SIMD)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;F1&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;veorq_u32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;veorq_u32&lt;&#x2F;span&gt;&lt;span&gt;(x, y), z)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;ROTL&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;n&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vorrq_u32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vshlq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(x, n), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vshrq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;32 &lt;&#x2F;span&gt;&lt;span&gt;- (n)))
&lt;&#x2F;span&gt;&lt;span&gt;alpha = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vaddq_u32&lt;&#x2F;span&gt;&lt;span&gt;(a1, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F1&lt;&#x2F;span&gt;&lt;span&gt;(b1, c1, d1));
&lt;&#x2F;span&gt;&lt;span&gt;alpha = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vaddq_u32&lt;&#x2F;span&gt;&lt;span&gt;(alpha, X[_n[i]]);
&lt;&#x2F;span&gt;&lt;span&gt;alpha = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vaddq_u32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ROTL&lt;&#x2F;span&gt;&lt;span&gt;(alpha, _r[i]), e1);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; err: argument to &amp;#39;__builtin_neon_vshlq_n_v&amp;#39; must be a constant integer
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; err: argument to &amp;#39;__builtin_neon_vshrq_n_v&amp;#39; must be a constant integer
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So, I have to use the macro version (C reference) because, in that case, the indexes are passed directly (the last argument in the FF macro) and expanded into constant values at compile time. Maybe this change is for the better (we will see why later).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;generic-round-macro&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#generic-round-macro&quot; aria-label=&quot;Anchor link for: generic-round-macro&quot;&gt;Generic Round Macro&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;If we look at RMD160 rounds, the same actions are performed, but with the following changes: base function, constant, data index, and rotation. In general, the round macro was shown above (I took a slightly different version from GitHub). My goal is to port the round macro to SIMD.&lt;&#x2F;p&gt;
&lt;p&gt;In the round, we add up 4 variables, perform a ROTL + another addition, and a separate ROTL for another variable. Since the &quot;+&quot; operation is not available in SIMD, we need to use special instructions.&lt;&#x2F;p&gt;
&lt;p&gt;I added some macros for vector addition and described the round itself:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;ADD2&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vaddq_u32&lt;&#x2F;span&gt;&lt;span&gt;(a, b)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;ADD3&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vaddq_u32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vaddq_u32&lt;&#x2F;span&gt;&lt;span&gt;(a, b), c)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;ADD4&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vaddq_u32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vaddq_u32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vaddq_u32&lt;&#x2F;span&gt;&lt;span&gt;(a, b), c), d)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RN&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;k&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;) \
&lt;&#x2F;span&gt;&lt;span&gt;  u = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ADD4&lt;&#x2F;span&gt;&lt;span&gt;(a, f, x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(k));  \
&lt;&#x2F;span&gt;&lt;span&gt;  a = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ADD2&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ROTL&lt;&#x2F;span&gt;&lt;span&gt;(u, r), e);            \
&lt;&#x2F;span&gt;&lt;span&gt;  c = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ROTL&lt;&#x2F;span&gt;&lt;span&gt;(c, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the macro, &lt;code&gt;a&lt;&#x2F;code&gt;, &lt;code&gt;b&lt;&#x2F;code&gt;, &lt;code&gt;c&lt;&#x2F;code&gt;, &lt;code&gt;d&lt;&#x2F;code&gt;, &lt;code&gt;e&lt;&#x2F;code&gt; are the state variables, &lt;code&gt;f&lt;&#x2F;code&gt; is the value after the base function computation, &lt;code&gt;x&lt;&#x2F;code&gt; is the uint32 index data for the current iteration, &lt;code&gt;k&lt;&#x2F;code&gt; is a constant, and &lt;code&gt;r&lt;&#x2F;code&gt; is the rotation value for ROTL.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;vdupq_n_u32(k)&lt;&#x2F;code&gt; loads a constant into a vector (the same value in all 4 lanes). Earlier, we wrote code to multiply a vector by a number, and for this purpose, &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.arm.com&#x2F;architectures&#x2F;instruction-sets&#x2F;intrinsics&#x2F;vmulq_n_u32&quot;&gt;&lt;code&gt;vmulq_n_u32&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; is used. Logically, the instruction to add a number to a vector should be &lt;code&gt;vaddq_n_u32&lt;&#x2F;code&gt;, but it &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.arm.com&#x2F;architectures&#x2F;instruction-sets&#x2F;intrinsics&#x2F;vaddq_n_u32&quot;&gt;does not exist&lt;&#x2F;a&gt;. Instead, it should be written in &lt;code&gt;vaddq_u32(vec1, vdupq_n_u32(2))&lt;&#x2F;code&gt; style (if anyone knows why this is the case – please leave a comment).&lt;&#x2F;p&gt;
&lt;p&gt;Then, based on this round macro, we can define left and right rounds. The code here is similar to any other macro implementation (except that I named the rounds as &lt;code&gt;Li&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;Ri&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;L1&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RN&lt;&#x2F;span&gt;&lt;span&gt;(a, b, c, d, e, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F1&lt;&#x2F;span&gt;&lt;span&gt;(b, c, d), x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, r)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;L2&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RN&lt;&#x2F;span&gt;&lt;span&gt;(a, b, c, d, e, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F2&lt;&#x2F;span&gt;&lt;span&gt;(b, c, d), x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x5A827999&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span&gt;, r)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;L3&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RN&lt;&#x2F;span&gt;&lt;span&gt;(a, b, c, d, e, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F3&lt;&#x2F;span&gt;&lt;span&gt;(b, c, d), x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x6ED9EBA1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span&gt;, r)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;L4&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RN&lt;&#x2F;span&gt;&lt;span&gt;(a, b, c, d, e, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F4&lt;&#x2F;span&gt;&lt;span&gt;(b, c, d), x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x8F1BBCDC&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span&gt;, r)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;L5&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RN&lt;&#x2F;span&gt;&lt;span&gt;(a, b, c, d, e, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F5&lt;&#x2F;span&gt;&lt;span&gt;(b, c, d), x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0xA953FD4E&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span&gt;, r)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;R1&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RN&lt;&#x2F;span&gt;&lt;span&gt;(a, b, c, d, e, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F5&lt;&#x2F;span&gt;&lt;span&gt;(b, c, d), x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x50A28BE6&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span&gt;, r)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;R2&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RN&lt;&#x2F;span&gt;&lt;span&gt;(a, b, c, d, e, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F4&lt;&#x2F;span&gt;&lt;span&gt;(b, c, d), x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x5C4DD124&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span&gt;, r)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;R3&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RN&lt;&#x2F;span&gt;&lt;span&gt;(a, b, c, d, e, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F3&lt;&#x2F;span&gt;&lt;span&gt;(b, c, d), x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x6D703EF3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span&gt;, r)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;R4&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RN&lt;&#x2F;span&gt;&lt;span&gt;(a, b, c, d, e, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F2&lt;&#x2F;span&gt;&lt;span&gt;(b, c, d), x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x7A6D76E9&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span&gt;, r)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;R5&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RN&lt;&#x2F;span&gt;&lt;span&gt;(a, b, c, d, e, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;F1&lt;&#x2F;span&gt;&lt;span&gt;(b, c, d), x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, r)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, using these macros, we can write the first iteration of the first round and compare it with the working implementation. If everything is OK, we can copy the entire round, check it, and then move on to the remaining rounds. I compared the result with the &lt;code&gt;print_check&lt;&#x2F;code&gt; function I created earlier.&lt;&#x2F;p&gt;
&lt;p&gt;First left round, first iteration:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; RMD160 initial constants
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;K1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x67452301
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;K2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0xEFCDAB89
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;K3 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x98BADCFE
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;K4 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0x10325476
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;K5 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0xC3D2E1F0
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;rmd160_block&lt;&#x2F;span&gt;&lt;span&gt;(uint32x4_t *&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;s&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;uint32_t &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;]) {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; a1-e1 left rounds state, a2-e2 right rounds state, u - temp varible used in RD macro
&lt;&#x2F;span&gt;&lt;span&gt;  uint32x4_t a1, b1, c1, d1, e1, a2, b2, c2, d2, e2, u;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Load initial constants
&lt;&#x2F;span&gt;&lt;span&gt;  a1 = a2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(K1);
&lt;&#x2F;span&gt;&lt;span&gt;  b1 = b2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(K2);
&lt;&#x2F;span&gt;&lt;span&gt;  c1 = c2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(K3);
&lt;&#x2F;span&gt;&lt;span&gt;  d1 = d2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(K4);
&lt;&#x2F;span&gt;&lt;span&gt;  e1 = e2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(K5);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  uint32x4_t w[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;]; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Load data to vector
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;; i++) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Load 4x32-bit integers from x[0][i], x[1][i], x[2][i], x[3][i]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; w[i] = vsetq_lane_u32(x[0][i], w[i], 0);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; w[i] = vsetq_lane_u32(x[1][i], w[i], 1);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; w[i] = vsetq_lane_u32(x[2][i], w[i], 2);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; w[i] = vsetq_lane_u32(x[3][i], w[i], 3);
&lt;&#x2F;span&gt;&lt;span&gt;    w[i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vld1q_u32&lt;&#x2F;span&gt;&lt;span&gt;(((uint32_t[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;]){x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][i], x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;][i], x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;][i], x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;][i]})); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; A bit faster
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;L1&lt;&#x2F;span&gt;&lt;span&gt;(a1, b1, c1, d1, e1, w[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;a1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, a1);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;b1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, b1);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;c1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, c1);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;d1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, d1);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;print_check&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;e1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, e1);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;uint32x4_t s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;] = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;}; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; initial state
&lt;&#x2F;span&gt;&lt;span&gt;s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(K1);
&lt;&#x2F;span&gt;&lt;span&gt;s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(K2);
&lt;&#x2F;span&gt;&lt;span&gt;s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(K3);
&lt;&#x2F;span&gt;&lt;span&gt;s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(K4);
&lt;&#x2F;span&gt;&lt;span&gt;s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(K5);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;uint32_t x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;] = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;}; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; data block, filled with zeros
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rmd160_block&lt;&#x2F;span&gt;&lt;span&gt;((uint32x4_t *)s, x);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It should be noted that hash functions are usually tested on zero data (for simplicity). Data in hash functions are processed in blocks. A block in RMD160 is 32×16 = 512 bits. &lt;code&gt;rmd160_block&lt;&#x2F;code&gt; can be called several times with the same state (which changes) and new data, for cases where you need to calculate the hash of a message larger than one round. In my task (address generation), all messages are placed in one block. The result of the first round compare to current implementation:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;&#x2F;&#x2F; a1: 1602f864 1602f864 1602f864 1602f864 vs c3d2e1f0
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; a1: efcdab89 efcdab89 efcdab89 efcdab89 vs 1602f864
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; a1: eb73fa62 eb73fa62 eb73fa62 eb73fa62 vs efcdab89
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; a1: 10325476 10325476 10325476 10325476 vs eb73fa62
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; a1: c3d2e1f0 c3d2e1f0 c3d2e1f0 c3d2e1f0 vs 10325476
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In general, these values ± are similar to the values from the current version, differing by one offset. This is not a problem, since there are 5 variables, and the offsets will be aligned by the end. It&#x27;s just a difference in the implementations.&lt;&#x2F;p&gt;
&lt;p&gt;I won&#x27;t write all the rounds, as there are 80 on each side (160 total) – it would result in an overly large code block. Left and right rounds are independent of each other and can be calculated in any order: either first all left &#x2F; all right, or alternating left &#x2F; right, or alternating iterations within a round. This will not affect the final result.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;finalizing-rmd160&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#finalizing-rmd160&quot; aria-label=&quot;Anchor link for: finalizing-rmd160&quot;&gt;Finalizing RMD160&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;At the end of RMD160 block, we need to combine the old state with the local state – this also involves three additions with index offsets.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;rmd160_block&lt;&#x2F;span&gt;&lt;span&gt;(uint32x4_t *&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;s&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;uint32_t &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;]) {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ... 160 rounds
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  uint32x4_t t = s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ADD3&lt;&#x2F;span&gt;&lt;span&gt;(s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;], c1, d2);
&lt;&#x2F;span&gt;&lt;span&gt;  s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ADD3&lt;&#x2F;span&gt;&lt;span&gt;(s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;], d1, e2);
&lt;&#x2F;span&gt;&lt;span&gt;  s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ADD3&lt;&#x2F;span&gt;&lt;span&gt;(s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;], e1, a2);
&lt;&#x2F;span&gt;&lt;span&gt;  s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ADD3&lt;&#x2F;span&gt;&lt;span&gt;(s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;], a1, b2);
&lt;&#x2F;span&gt;&lt;span&gt;  s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ADD3&lt;&#x2F;span&gt;&lt;span&gt;(t, b1, c2);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The final step is to change the endianness of the values (RMD160 uses a different endianness) and unload the values from the vector into the resulting array.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ... init &amp;amp; rmd160_block
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;; ++i) {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; swap32 for uint32x4_t (can it be shorter?)
&lt;&#x2F;span&gt;&lt;span&gt;  s[i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vreinterpretq_u32_u8&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vrev32q_u8&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vreinterpretq_u8_u32&lt;&#x2F;span&gt;&lt;span&gt;(s[i])));
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;uint32_t r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;] = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;}; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; result stored as 4x5 uint32_t
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;; i++) { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; load it from uint32x4_t
&lt;&#x2F;span&gt;&lt;span&gt;  r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vgetq_lane_u32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vgetq_lane_u32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vgetq_lane_u32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vgetq_lane_u32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That is all – &lt;code&gt;r&lt;&#x2F;code&gt; can be used further where needed (&lt;code&gt;r[0]&lt;&#x2F;code&gt;, &lt;code&gt;r[1]&lt;&#x2F;code&gt;, &lt;code&gt;r[2]&lt;&#x2F;code&gt;, &lt;code&gt;r[3]&lt;&#x2F;code&gt; are the computed hashes — four at once).&lt;&#x2F;p&gt;
&lt;p&gt;To summarize this section, the complete parallel RMD160 algorithm looks like this:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Initialize a state of length 160 bits × 4 lanes (&lt;code&gt;uint32x4_t s[5]&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;Split the message (data) into blocks of 512 bits × 4 lanes (&lt;code&gt;uint32_t x[4][16]&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;Iterate RMD160 rounds until the data runs out (&lt;code&gt;rmd160_block&lt;&#x2F;code&gt; reads the data into the vector itself).&lt;&#x2F;li&gt;
&lt;li&gt;Change the endianness in the final state.&lt;&#x2F;li&gt;
&lt;li&gt;Unload the vector of the final state into a hash array (&lt;code&gt;int32_t r[4][5]&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;performance-of-rmd160-simd&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#performance-of-rmd160-simd&quot; aria-label=&quot;Anchor link for: performance-of-rmd160-simd&quot;&gt;Performance of RMD160 SIMD&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Now, it&#x27;s time to measure the performance of this code – to compare the performance of the original and SIMD implementations. For this purpose, I created a small benchmark:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span&gt;size_t &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;tsnow&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; timespec ts;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;clock_gettime&lt;&#x2F;span&gt;&lt;span&gt;(CLOCK_REALTIME, &amp;amp;ts);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; ts.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tv_sec &lt;&#x2F;span&gt;&lt;span&gt;* &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1000 &lt;&#x2F;span&gt;&lt;span&gt;+ ts.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tv_nsec &lt;&#x2F;span&gt;&lt;span&gt;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1e6&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;rmd160_simd&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;  uint32_t r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;] = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;  uint32_t x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;] = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  size_t stime = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tsnow&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;  size_t iters = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1000 &lt;&#x2F;span&gt;&lt;span&gt;* &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1000 &lt;&#x2F;span&gt;&lt;span&gt;* &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;32&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(size_t i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; iters; ++i) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rmd160_4w&lt;&#x2F;span&gt;&lt;span&gt;(r, x);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;double&lt;&#x2F;span&gt;&lt;span&gt; dt = (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tsnow&lt;&#x2F;span&gt;&lt;span&gt;() - stime) &#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1000.0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;double&lt;&#x2F;span&gt;&lt;span&gt; ir = iters &#x2F; dt &#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1000000&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;double&lt;&#x2F;span&gt;&lt;span&gt; hr = ir * &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; 4 hash per iter
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;M it&#x2F;s ~ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;M h&#x2F;s ~ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, ir, hr, dt);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;s[0]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%08x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;s[1]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%08x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;s[2]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%08x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;s[3]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%08x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;s[4]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%08x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;rmd160_naive&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;  uint32_t s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;] = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;  uint32_t x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;] = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  size_t stime = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tsnow&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;  size_t iters = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1000 &lt;&#x2F;span&gt;&lt;span&gt;* &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1000 &lt;&#x2F;span&gt;&lt;span&gt;* &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;32&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(size_t i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; iters; ++i) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rmd160_1w&lt;&#x2F;span&gt;&lt;span&gt;(s, x);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;double&lt;&#x2F;span&gt;&lt;span&gt; dt = (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tsnow&lt;&#x2F;span&gt;&lt;span&gt;() - stime) &#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1000.0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;double&lt;&#x2F;span&gt;&lt;span&gt; ir = iters &#x2F; dt &#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1000000&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;double&lt;&#x2F;span&gt;&lt;span&gt; hr = ir * &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; 1 hash per iter
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;M it&#x2F;s ~ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;M h&#x2F;s ~ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, ir, hr, dt);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;s[0]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%08x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;s[1]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%08x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;s[2]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%08x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;s[3]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%08x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;s[4]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%08x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I compiled both programs with &lt;code&gt;-O3&lt;&#x2F;code&gt; and ran them (on a basic Apple M2):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; clang&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -O3 -march&lt;&#x2F;span&gt;&lt;span&gt;=native .&#x2F;lib&#x2F;rmd160.c &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;.&#x2F;a.out &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# original
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;5.50M&lt;&#x2F;span&gt;&lt;span&gt; it&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 5.50M h&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 5.81s
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; clang&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -O3 -march&lt;&#x2F;span&gt;&lt;span&gt;=native .&#x2F;lib&#x2F;rmd160s.c &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;.&#x2F;a.out &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# neon
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;2.14M&lt;&#x2F;span&gt;&lt;span&gt; it&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 8.55M h&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 14.98s
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Neon version (128-bit &#x2F; 4 lanes) is 55% faster. This is a great result, but it&#x27;s unfortunate that M-chips don&#x27;t have SVE for 256&#x2F;512 bits (8&#x2F;16 lanes), as that would make it even better!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;one-more-thing&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#one-more-thing&quot; aria-label=&quot;Anchor link for: one-more-thing&quot;&gt;One More Thing&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;While I was writing about the results above, I became &lt;strong&gt;curious&lt;&#x2F;strong&gt; to see what would happen if I changed the order of the rounds in RMD160. The original order of rounds was as follows: first all left rounds, then all right rounds. I thought this was good for the processor, because it seemed to require less &quot;context switching&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;I changed the order of rounds to alternating left and right rounds (L1 &#x2F; R1, L2 &#x2F; R2), and the performance increased significantly. Initially, I thought there was a data error, but &lt;code&gt;print_check&lt;&#x2F;code&gt; (as tests) confirms everything is fine.&lt;&#x2F;p&gt;
&lt;p&gt;I decided to try alternating iterations (L1_1 R1_1 L1_2 R1_2 R1_2, etc.). To be honest, rearranging 160 lines is not the most fun, but the result surprised me even more.&lt;&#x2F;p&gt;
&lt;p&gt;Comparison of different round&#x2F;iteration placements (3 tests of RMD160 function itself and a full cycle of &lt;code&gt;ecloop&lt;&#x2F;code&gt; logic):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# L1_1 L2_2 .. L5_16 R1_1 R2_2 .. R5_16 (+56%)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;2.25M&lt;&#x2F;span&gt;&lt;span&gt; it&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 9.02M h&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 14.19s
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;2.23M&lt;&#x2F;span&gt;&lt;span&gt; it&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 8.93M h&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 14.33s
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;2.23M&lt;&#x2F;span&gt;&lt;span&gt; it&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 8.94M h&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 14.32s
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ecloop&lt;&#x2F;span&gt;&lt;span&gt; (addr33 x 8 core) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 19.53M it&#x2F;s (+22%)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# L1_1-L1_16 R1_1-R1_16 L2_1-L2_16 .. (+165%)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;3.70M&lt;&#x2F;span&gt;&lt;span&gt; it&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 14.80M h&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 8.65s
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;3.85M&lt;&#x2F;span&gt;&lt;span&gt; it&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 15.42M h&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 8.30s
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;3.87M&lt;&#x2F;span&gt;&lt;span&gt; it&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 15.46M h&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 8.28s
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ecloop&lt;&#x2F;span&gt;&lt;span&gt; (addr33 x 8 core) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 22.46M it&#x2F;s (+40%)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# L1_1 R1_1 L1_2 R1_2 .. L5_16 R5_16 (+175%)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;3.96M&lt;&#x2F;span&gt;&lt;span&gt; it&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 15.82M h&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 8.09s
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;3.94M&lt;&#x2F;span&gt;&lt;span&gt; it&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 15.78M h&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 8.11s
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;3.94M&lt;&#x2F;span&gt;&lt;span&gt; it&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 15.76M h&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 8.12s
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ecloop&lt;&#x2F;span&gt;&lt;span&gt; (addr33 x 8 core) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 24.83M it&#x2F;s (+55%)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It&#x27;s a mystery to me why it works this way, and maybe there is an even more effective arrangement. Who knows? Please, write in the comments.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;support-for-avx2-amd64&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#support-for-avx2-amd64&quot; aria-label=&quot;Anchor link for: support-for-avx2-amd64&quot;&gt;Support for AVX2 (AMD64)&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Initially, I didn&#x27;t plan to implement this, but RMD160 algorithm using macros was quite abstract, and further porting to AVX2 seemed fairly simple. The main difference between AVX2 and Neon (aside from the different instruction sets) is the vector size – 256 bits vs 128 bits – which allows us to process 8 hashes in parallel (vs 4 in Neon).&lt;&#x2F;p&gt;
&lt;p&gt;Currently, the following Neon instructions are used directly in the algorithm code: vector type (&lt;code&gt;uint32x4_t&lt;&#x2F;code&gt;), state initialization via &lt;code&gt;vdupq_n_u32&lt;&#x2F;code&gt;, endian-swap, and load &#x2F; dump data into the vector.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m moving these things to macros (just in case, I added &lt;code&gt;RMD_&lt;&#x2F;code&gt; prefix to avoid conflicts with other files):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;RMD_LEN &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; vector length
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;RMD_VEC uint32x4_t           &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; vector type
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_LD_NUM&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vdupq_n_u32&lt;&#x2F;span&gt;&lt;span&gt;(x) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; load same number into all lanes
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_SWAP&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vreinterpretq_u32_u8&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vrev32q_u8&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vreinterpretq_u8_u32&lt;&#x2F;span&gt;&lt;span&gt;(x)))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_LOAD&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vld1q_u32&lt;&#x2F;span&gt;&lt;span&gt;(((uint32_t[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;]){x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][i], x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;][i], x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;][i], x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;][i]}))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_DUMP&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;s&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span&gt;)                                                                        \
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;do &lt;&#x2F;span&gt;&lt;span&gt;{                                                                                           \
&lt;&#x2F;span&gt;&lt;span&gt;    r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vgetq_lane_u32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;);                                                           \
&lt;&#x2F;span&gt;&lt;span&gt;    r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vgetq_lane_u32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);                                                           \
&lt;&#x2F;span&gt;&lt;span&gt;    r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vgetq_lane_u32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;);                                                           \
&lt;&#x2F;span&gt;&lt;span&gt;    r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vgetq_lane_u32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;);                                                           \
&lt;&#x2F;span&gt;&lt;span&gt;  } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;while &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And update the current code to something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;rmd160_block&lt;&#x2F;span&gt;&lt;span&gt;(RMD_VEC *&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;s&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;uint32_t &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;[RMD_LEN][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;]) {
&lt;&#x2F;span&gt;&lt;span&gt;  RMD_VEC a1, b1, c1, d1, e1, a2, b2, c2, d2, e2, u;
&lt;&#x2F;span&gt;&lt;span&gt;  a1 = a2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RMD_LD_NUM&lt;&#x2F;span&gt;&lt;span&gt;(RMD_K1);
&lt;&#x2F;span&gt;&lt;span&gt;  b1 = b2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RMD_LD_NUM&lt;&#x2F;span&gt;&lt;span&gt;(RMD_K2);
&lt;&#x2F;span&gt;&lt;span&gt;  c1 = c2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RMD_LD_NUM&lt;&#x2F;span&gt;&lt;span&gt;(RMD_K3);
&lt;&#x2F;span&gt;&lt;span&gt;  d1 = d2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RMD_LD_NUM&lt;&#x2F;span&gt;&lt;span&gt;(RMD_K4);
&lt;&#x2F;span&gt;&lt;span&gt;  e1 = e2 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RMD_LD_NUM&lt;&#x2F;span&gt;&lt;span&gt;(RMD_K5);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  RMD_VEC w[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;; i++) w[i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RMD_LOAD&lt;&#x2F;span&gt;&lt;span&gt;(x, i);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ... rounds and iterations
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; new function to process full single block
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;rmd160_batch&lt;&#x2F;span&gt;&lt;span&gt;(uint32_t &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;[RMD_LEN][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;uint32_t &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;[RMD_LEN][&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;]) {
&lt;&#x2F;span&gt;&lt;span&gt;  RMD_VEC s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;] = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;}; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; load initial state
&lt;&#x2F;span&gt;&lt;span&gt;  s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RMD_LD_NUM&lt;&#x2F;span&gt;&lt;span&gt;(RMD_K1);
&lt;&#x2F;span&gt;&lt;span&gt;  s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RMD_LD_NUM&lt;&#x2F;span&gt;&lt;span&gt;(RMD_K2);
&lt;&#x2F;span&gt;&lt;span&gt;  s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RMD_LD_NUM&lt;&#x2F;span&gt;&lt;span&gt;(RMD_K3);
&lt;&#x2F;span&gt;&lt;span&gt;  s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RMD_LD_NUM&lt;&#x2F;span&gt;&lt;span&gt;(RMD_K4);
&lt;&#x2F;span&gt;&lt;span&gt;  s[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RMD_LD_NUM&lt;&#x2F;span&gt;&lt;span&gt;(RMD_K5);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rmd160_block&lt;&#x2F;span&gt;&lt;span&gt;((RMD_VEC *)s, x);                     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; round
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;; ++i) s[i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RMD_SWAP&lt;&#x2F;span&gt;&lt;span&gt;(s[i]); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; change endian
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;; ++i) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RMD_DUMP&lt;&#x2F;span&gt;&lt;span&gt;(r, s, i);     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; dump data to array
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Of course, it&#x27;s already quite magical, but there aren&#x27;t really many changes. Now, I should add redefined macros for AVX2. In addition, I wrapped a series of architecture-specific macros in &lt;code&gt;#ifdef&lt;&#x2F;code&gt;. In fact, I have a single codebase for RMD160 algorithm, and the necessary macros are included depending on which processor the program is being compiled for.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#if defined&lt;&#x2F;span&gt;&lt;span&gt;(__aarch64__) &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;defined&lt;&#x2F;span&gt;&lt;span&gt;(__ARM_NEON)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;arm_neon.h&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;RMD_LEN &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; vector length
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;RMD_VEC uint32x4_t           &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; vector type
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ... move all current Neon related macros here
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#elif defined&lt;&#x2F;span&gt;&lt;span&gt;(__x86_64__) &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;defined&lt;&#x2F;span&gt;&lt;span&gt;(__AVX2__)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;immintrin.h&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;RMD_LEN &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;RMD_VEC __m256i
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_LD_NUM&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_set1_epi32&lt;&#x2F;span&gt;&lt;span&gt;(x)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_SWAP&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;)                                                                              \
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_shuffle_epi8&lt;&#x2F;span&gt;&lt;span&gt;((x), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_setr_epi8&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;9&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;,    \
&lt;&#x2F;span&gt;&lt;span&gt;                                              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;19&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;17&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;22&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;27&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;26&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;25&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;,  \
&lt;&#x2F;span&gt;&lt;span&gt;                                              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;31&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;30&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;29&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;28&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_LOAD&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span&gt;)                                                                           \
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_set_epi32&lt;&#x2F;span&gt;&lt;span&gt;(x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][i], x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;][i], x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;][i], x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;][i], x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;][i], x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;][i], x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;][i], x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;][i])
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_DUMP&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;s&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span&gt;)                                                                        \
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;do &lt;&#x2F;span&gt;&lt;span&gt;{                                                                                           \
&lt;&#x2F;span&gt;&lt;span&gt;      r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_extract_epi32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;);                                                     \
&lt;&#x2F;span&gt;&lt;span&gt;      r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_extract_epi32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);                                                     \
&lt;&#x2F;span&gt;&lt;span&gt;      r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_extract_epi32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;);                                                     \
&lt;&#x2F;span&gt;&lt;span&gt;      r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_extract_epi32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;);                                                     \
&lt;&#x2F;span&gt;&lt;span&gt;      r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_extract_epi32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;);                                                     \
&lt;&#x2F;span&gt;&lt;span&gt;      r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_extract_epi32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;);                                                     \
&lt;&#x2F;span&gt;&lt;span&gt;      r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_extract_epi32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;);                                                     \
&lt;&#x2F;span&gt;&lt;span&gt;      r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;][i] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_extract_epi32&lt;&#x2F;span&gt;&lt;span&gt;(s[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;);                                                     \
&lt;&#x2F;span&gt;&lt;span&gt;    } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;while &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;_mm256_not_si256&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_xor_si256&lt;&#x2F;span&gt;&lt;span&gt;((x), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_set1_epi32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0xffffffff&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_F1&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_xor_si256&lt;&#x2F;span&gt;&lt;span&gt;(x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_xor_si256&lt;&#x2F;span&gt;&lt;span&gt;(y, z))
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_F2&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_or_si256&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_and_si256&lt;&#x2F;span&gt;&lt;span&gt;(x, y), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_andnot_si256&lt;&#x2F;span&gt;&lt;span&gt;(x, z))
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_F3&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_xor_si256&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_or_si256&lt;&#x2F;span&gt;&lt;span&gt;(x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_not_si256&lt;&#x2F;span&gt;&lt;span&gt;(y)), z)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_F4&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_or_si256&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_and_si256&lt;&#x2F;span&gt;&lt;span&gt;(x, z), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_andnot_si256&lt;&#x2F;span&gt;&lt;span&gt;(z, y))
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_F5&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_xor_si256&lt;&#x2F;span&gt;&lt;span&gt;(x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_or_si256&lt;&#x2F;span&gt;&lt;span&gt;(y, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_not_si256&lt;&#x2F;span&gt;&lt;span&gt;(z)))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_ROTL&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;n&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_or_si256&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_slli_epi32&lt;&#x2F;span&gt;&lt;span&gt;(x, n), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_srli_epi32&lt;&#x2F;span&gt;&lt;span&gt;(x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;32 &lt;&#x2F;span&gt;&lt;span&gt;- (n)))
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_ADD2&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_add_epi32&lt;&#x2F;span&gt;&lt;span&gt;(a, b)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_ADD3&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_add_epi32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_add_epi32&lt;&#x2F;span&gt;&lt;span&gt;(a, b), c)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_ADD4&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_add_epi32&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_add_epi32&lt;&#x2F;span&gt;&lt;span&gt;(a, b), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;_mm256_add_epi32&lt;&#x2F;span&gt;&lt;span&gt;(c, d))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#else
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#error &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Unsupported arch for RIPEMD-160 (AVX2 or NEON required)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#endif
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The main differences are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A different header file.&lt;&#x2F;li&gt;
&lt;li&gt;A different vector type (8 lanes instead of 4 in Neon) and different names for intrinsics.&lt;&#x2F;li&gt;
&lt;li&gt;AVX2 has no Bitwise NOT, so I had to add it separately as &lt;code&gt;_mm256_not_si256&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;No separate function for endian-swap, but there is a more generalized function to rearrange bits in a given order: &lt;code&gt;_mm256_shuffle_epi8&lt;&#x2F;code&gt; (the first argument specifies where to rearrange the bits, and the second specifies how to rearrange them).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;_mm256_set_epi32&lt;&#x2F;code&gt; makes it more convenient to load data into different lanes, while in Neon we had to use a temporary array (the variant with setting each lane separately (&lt;code&gt;vsetq_lane_u32&lt;&#x2F;code&gt;) is slower).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The rewriting of the macros was mostly handled by GPT; I just checked the correctness once again.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;performance-of-avx2-version&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#performance-of-avx2-version&quot; aria-label=&quot;Anchor link for: performance-of-avx2-version&quot;&gt;Performance of AVX2 Version&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I have a small fanless PC running Linux on an Intel N100, which I use for native application testing. I ran the benchmark written earlier on it and got the following results:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; clang&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -O3 -march&lt;&#x2F;span&gt;&lt;span&gt;=native .&#x2F;lib&#x2F;rmd160.c &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;.&#x2F;a.out &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# original (on Intel N100)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;4.26M&lt;&#x2F;span&gt;&lt;span&gt; it&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 4.26M h&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 7.51s
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; clang&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -O3 -march&lt;&#x2F;span&gt;&lt;span&gt;=native .&#x2F;lib&#x2F;rmd160s.c &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;.&#x2F;a.out &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# avx2 (on Intel N100)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;2.25M&lt;&#x2F;span&gt;&lt;span&gt; it&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 17.96M h&#x2F;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt; 14.25s
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;8 lanes of AVX2 and the correct arrangement of rounds in the algorithm (zebra iterations) result in a 320% increase in the number of hashes per second compared to the original code. What&#x27;s interesting is that AVX2 on the Intel N100 runs 20% faster than Neon on the Apple M2 (mainly because of the vector size). Overall &lt;code&gt;ecloop&lt;&#x2F;code&gt; speedup: &lt;code&gt;5.45M it&#x2F;s vs 7.73M it&#x2F;s (+42%)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fallback-implementation-for-older-processors-vms&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#fallback-implementation-for-older-processors-vms&quot; aria-label=&quot;Anchor link for: fallback-implementation-for-older-processors-vms&quot;&gt;Fallback Implementation for Older Processors &#x2F; VMs&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In the &lt;code&gt;#ifdef&lt;&#x2F;code&gt; above, I left the &lt;code&gt;#else&lt;&#x2F;code&gt; section with &lt;code&gt;#error&lt;&#x2F;code&gt; to prevent compilation on unsupported systems. In general, this is not ideal, and I would like the program to work everywhere (mainly for potential runs in VMs). Since the whole algorithm is already written in macros, adding a new implementation is not difficult. I simply redefine all macros to use a vector size of 1 and &lt;code&gt;uint32_t&lt;&#x2F;code&gt; as the &quot;vector&quot; type. In reality, the program will work with a single array, which, from a memory perspective in C, is essentially the same as just using &lt;code&gt;uint32_t&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ... #ifdef for neon &#x2F; avx2
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#else
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#warning &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Fallback RIPEMD-160 implementation used. AVX2 or NEON required for SIMD&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;RMD_LEN &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span&gt;RMD_VEC uint32_t
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_LD_NUM&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;) x
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_SWAP&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;__builtin_bswap32&lt;&#x2F;span&gt;&lt;span&gt;(x)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_LOAD&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span&gt;) x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][i]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_DUMP&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;s&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span&gt;) r[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][i] = s[i]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_F1&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) ((x) ^ (y) ^ (z))
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_F2&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) (((x) &amp;amp; (y)) | (~(x) &amp;amp; (z)))
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_F3&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) (((x) | ~(y)) ^ (z))
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_F4&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) (((x) &amp;amp; (z)) | ((y) &amp;amp; ~(z)))
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_F5&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;) ((x) ^ ((y) | ~(z)))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_ROTL&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;n&lt;&#x2F;span&gt;&lt;span&gt;) (((x) &amp;lt;&amp;lt; (n)) | ((x) &amp;gt;&amp;gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;32 &lt;&#x2F;span&gt;&lt;span&gt;- (n))))
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_ADD2&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;) (a + b)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_ADD3&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;) (a + b + c)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;RMD_ADD4&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;) (a + b + c + d)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;#endif
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I ran it and checked it – it works correctly, except that the speed became a bit faster due to the new order of rounds. It is not difficult to add an implementation for AVX512 (16 lanes) in the same way, but I don&#x27;t have a processor to test it, so I didn&#x27;t do it. Also, the article was already getting quite long, so I’m wrapping it up here.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;fin&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#fin&quot; aria-label=&quot;Anchor link for: fin&quot;&gt;Fin&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;SIMD programming turned out to be easier than it seemed. The necessary intrinsics can be &quot;Googled&quot; in GPT; it is difficult to search for them yourself because there are thousands of combinations. RMD160 itself is mostly used in cryptocurrencies (at least I don&#x27;t know of other popular use cases), so the usefulness of the obtained code outside of the learning factor is questionable.&lt;&#x2F;p&gt;
&lt;p&gt;SIMD calculations give a good boost to execution speed, but, of course, you should take into account the specifics of the task: you need to have a lot of data to process, and these data should have the same size. It makes no sense to use SIMD if some data to be hashed fits into one block and others into 100 (for example, when processing files). Also, the main program should be able to process data in batches.&lt;&#x2F;p&gt;
&lt;p&gt;The final code as a single file is available on &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;ecloop&#x2F;blob&#x2F;main&#x2F;lib&#x2F;rmd160s.c&quot;&gt;Github&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>From iTerm To WezTerm</title>
        <published>2025-01-09T00:00:00+00:00</published>
        <updated>2025-01-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/from-iterm-to-wezterm/"/>
        <id>https://vladkens.cc/from-iterm-to-wezterm/</id>
        
        <content type="html" xml:base="https://vladkens.cc/from-iterm-to-wezterm/">&lt;p&gt;&lt;img src=&quot;&#x2F;20250109-0.png&quot; alt=&quot;WezTerm&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For many years, I used &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gnachman&#x2F;iTerm2&quot;&gt;iTerm2&lt;&#x2F;a&gt; as my main terminal emulator and probably spent hundreds of hours in it. Overall, I was satisfied with it, despite some strange recent updates like adding AI features, KeyChain integration, and &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=42579472&quot;&gt;security vulnerabilities&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In recent years, new terminal emulators have appeared. I tried using them mainly for testing &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&quot;&gt;macmon&lt;&#x2F;a&gt;. A couple of years ago, I tried switching to &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kovidgoyal&#x2F;kitty&quot;&gt;kitty&lt;&#x2F;a&gt;, which was faster due to GPU acceleration. However, it required too much customization and still looked very non-native for macOS. GPU acceleration was added to iTerm as well, so I stayed with it.&lt;&#x2F;p&gt;
&lt;p&gt;I also tried &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;alacritty&#x2F;alacritty&quot;&gt;Alacritty&lt;&#x2F;a&gt;, but it is very basic and lacks the features I need. Recently, I tested &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ghostty-org&#x2F;ghostty&quot;&gt;Ghostty&lt;&#x2F;a&gt;, which has gained huge attention – it has nice defaults, but its RAM usage is concerning (around 250MB per empty tab). Currently, it also lacks &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ghostty-org&#x2F;ghostty&#x2F;issues&#x2F;189&quot;&gt;buffer search&lt;&#x2F;a&gt;, which makes the terminal useless for me.&lt;&#x2F;p&gt;
&lt;p&gt;I heard a lot of positive feedback about &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;wez&#x2F;wezterm&quot;&gt;WezTerm&lt;&#x2F;a&gt; from &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bobuk&quot;&gt;bobuk&lt;&#x2F;a&gt;. So I decided to try it out and use it for some time – and I am very satisfied with it.&lt;&#x2F;p&gt;
&lt;p&gt;The next part of the article will be about how to make WezTerm understandable for iTerm users to try it or switch completely.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;initial&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#initial&quot; aria-label=&quot;Anchor link for: initial&quot;&gt;Initial&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;WezTerm can be installed from Homebrew:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span&gt; install&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --cask&lt;&#x2F;span&gt;&lt;span&gt; wezterm
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When you first open WezTerm, it looks plain, non-native, and not very functional. But actually, it has everything you need. This is because WezTerm is cross-platform, unlike iTerm2, so the author left minimal default settings, leaving the rest of the configuration to the user. My goal is to achieve a similar experience in WezTerm as I had in iTerm.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;20250109-1.png&quot; alt=&quot;WezTerm on first launch&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;WezTerm does not have a graphical interface for configuration, and the setup is done through a Lua file (this is unusual for me, but Vim users are familiar with it). The configuration file can be located at &lt;code&gt;~&#x2F;.wezterm.lua&lt;&#x2F;code&gt; or &lt;code&gt;~&#x2F;.config&#x2F;wezterm&#x2F;wezterm.lua&lt;&#x2F;code&gt;. I prefer the second path because it is where &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fish-shell&#x2F;fish-shell&quot;&gt;Fish&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starship&#x2F;starship&quot;&gt;starship&lt;&#x2F;a&gt; store configs too.&lt;&#x2F;p&gt;
&lt;p&gt;Create a configuration file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;mkdir -p ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;.config&#x2F;wezterm&#x2F; &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;touch ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;.config&#x2F;wezterm&#x2F;wezterm.lua
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And then add the boilerplate code for configuration:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;lua&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-lua &quot;&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wezterm &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;require &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;wezterm&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wezterm&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config_builder&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;action &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wezterm&lt;&#x2F;span&gt;&lt;span&gt;.action
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;-- (here will be added actual configuration)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;appearance&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#appearance&quot; aria-label=&quot;Anchor link for: appearance&quot;&gt;Appearance&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;First, I want to change the default font, its size, and disable ligatures (because it&#x27;s important to see the actual characters in case of some logs).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;lua&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-lua &quot;&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;.font = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wezterm&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;font &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;family &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;JetBrains Mono&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;weight &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Medium&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;harfbuzz_features &lt;&#x2F;span&gt;&lt;span&gt;= { &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;calt=0&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;clig=0&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;liga=0&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; }, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;-- disable ligatures
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;.font_size = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;14.0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;.line_height = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1.0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Save the file, and the changes should be applied immediately (yes, no reload required!).&lt;&#x2F;p&gt;
&lt;p&gt;Next, I want to change the theme and set it to follow the current system theme automatically. For the past year, I have been using &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;catppuccin&#x2F;catppuccin&quot;&gt;Catppuccin&lt;&#x2F;a&gt; themes, and I am very happy with them. They rarely have issues where some text colors blend with the background. To make the theme switch automatically based on the current system theme, we need to write a small Lua function (I copied it from the documentation):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;lua&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-lua &quot;&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local function &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;scheme_for_appearance&lt;&#x2F;span&gt;&lt;span&gt;(appearance)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;appearance&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;find &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Dark&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;then
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Catppuccin Macchiato&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Catppuccin Latte&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;.color_scheme = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scheme_for_appearance&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wezterm&lt;&#x2F;span&gt;&lt;span&gt;.gui.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;get_appearance&lt;&#x2F;span&gt;&lt;span&gt;())
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I forgot to mention that the Catppuccin theme, like many other popular themes, is pre-installed in WezTerm, so you don&#x27;t need to install it separately like in iTerm, which is very cool. Of course, you can also set up &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wezfurlong.org&#x2F;wezterm&#x2F;config&#x2F;appearance.html#defining-your-own-colors&quot;&gt;your own colors&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The default padding also seems a bit large, so let&#x27;s make it smaller. I also had a Blinking Line Cursor (I don&#x27;t remember if this is the default or not in iTerm). Let&#x27;s set both configurations:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;lua&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-lua &quot;&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;.window_padding = { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;left &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.5cell&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;right &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.5cell&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;top &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.5cell&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;bottom &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.5cell&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;.default_cursor_style = &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;BlinkingBar&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;window-style&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#window-style&quot; aria-label=&quot;Anchor link for: window-style&quot;&gt;Window style&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In iTerm, I used the Minimal theme to save vertical space for tabs. We can do the same in WezTerm (the default tabs don&#x27;t look very good). Also possible to add some transparency and blur to the window. I didn&#x27;t use this in iTerm, but let&#x27;s try it now:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;lua&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-lua &quot;&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;.window_decorations = &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;RESIZE|INTEGRATED_BUTTONS&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;.window_background_opacity = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0.96
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;.macos_window_background_blur = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;20
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;20250109-2.png&quot; alt=&quot;WezTerm tabs decoration&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;maximize-on-start-up&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#maximize-on-start-up&quot; aria-label=&quot;Anchor link for: maximize-on-start-up&quot;&gt;Maximize on start-up&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In iTerm, I usually set large values for Cols&#x2F;Rows to make the start window bigger. This approach is a bit outdated, so let&#x27;s make the window open in full screen when the terminal starts.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;lua&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-lua &quot;&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;-- https:&#x2F;&#x2F;github.com&#x2F;wez&#x2F;wezterm&#x2F;issues&#x2F;3299#issuecomment-2145712082
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wezterm&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;on&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;gui-startup&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span&gt;(cmd)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;active &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wezterm&lt;&#x2F;span&gt;&lt;span&gt;.gui.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;screens&lt;&#x2F;span&gt;&lt;span&gt;().active
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tab&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;pane&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;window &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wezterm&lt;&#x2F;span&gt;&lt;span&gt;.mux.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;spawn_window&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cmd &lt;&#x2F;span&gt;&lt;span&gt;or {})
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;window&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;gui_window&lt;&#x2F;span&gt;&lt;span&gt;():&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;set_position&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;active&lt;&#x2F;span&gt;&lt;span&gt;.x, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;active&lt;&#x2F;span&gt;&lt;span&gt;.y)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;window&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;gui_window&lt;&#x2F;span&gt;&lt;span&gt;():&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;set_inner_size&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;active&lt;&#x2F;span&gt;&lt;span&gt;.width, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;active&lt;&#x2F;span&gt;&lt;span&gt;.height)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;end&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;key-bindings&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#key-bindings&quot; aria-label=&quot;Anchor link for: key-bindings&quot;&gt;Key bindings&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Finally, the most important part is setting up hotkeys – it&#x27;s hard to give up what you&#x27;ve been used to for years. An important thing for me is Split Panels with &lt;code&gt;Cmd + D&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;Cmd + Shift + D&lt;&#x2F;code&gt;. &lt;code&gt;Cmd + W&lt;&#x2F;code&gt; should close the current active panel, not the whole tab. &lt;code&gt;Cmd + K&lt;&#x2F;code&gt; – clear the current screen. &lt;code&gt;Cmd + ←&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;Cmd + →&lt;&#x2F;code&gt; for start&#x2F;end of the line. I think these are all defaults from iTerm, so let&#x27;s make them the same in WezTerm:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;lua&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-lua &quot;&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;.keys = {
&lt;&#x2F;span&gt;&lt;span&gt;  { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;key &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mods &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CMD|SHIFT&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;action &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;action&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;SplitVertical &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;domain &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CurrentPaneDomain&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; } },
&lt;&#x2F;span&gt;&lt;span&gt;  { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;key &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mods &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;action &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;action&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;SplitHorizontal &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;domain &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CurrentPaneDomain&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; } },
&lt;&#x2F;span&gt;&lt;span&gt;  { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;key &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;k&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mods &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;action &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;action&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ClearScrollback &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ScrollbackAndViewport&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; },
&lt;&#x2F;span&gt;&lt;span&gt;  { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;key &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;w&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mods &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;action &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;action&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CloseCurrentPane &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;confirm &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;false &lt;&#x2F;span&gt;&lt;span&gt;} },
&lt;&#x2F;span&gt;&lt;span&gt;  { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;key &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;w&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mods &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CMD|SHIFT&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;action &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;action&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;CloseCurrentTab &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;confirm &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;false &lt;&#x2F;span&gt;&lt;span&gt;} },
&lt;&#x2F;span&gt;&lt;span&gt;  { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;key &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;LeftArrow&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mods &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;action &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;action&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;SendKey &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;key &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Home&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; } },
&lt;&#x2F;span&gt;&lt;span&gt;  { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;key &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;RightArrow&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mods &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;action &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;action&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;SendKey &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;key &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;End&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; } },
&lt;&#x2F;span&gt;&lt;span&gt;  { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;key &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mods &lt;&#x2F;span&gt;&lt;span&gt;= &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CMD|SHIFT&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;action &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;action&lt;&#x2F;span&gt;&lt;span&gt;.ActivateCommandPalette },
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;WezTerm also has a Command Execution menu. I haven&#x27;t used it much yet, but just in case, I bind it to the same keys as in VSCode &#x2F; Zed – &lt;code&gt;Cmd + Shift + P&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note: In the configuration, the &lt;code&gt;key&lt;&#x2F;code&gt; value is case-sensitive, so &lt;code&gt;{ key = &#x27;d&#x27;, ... }&lt;&#x2F;code&gt; and &lt;code&gt;{ key = &#x27;D&#x27;, ... }&lt;&#x2F;code&gt; are different things (basically &lt;code&gt;key=&#x27;D&#x27;&lt;&#x2F;code&gt; is the same as &lt;code&gt;key=&#x27;d&#x27;, mods=&#x27;SHIFT&#x27;&lt;&#x2F;code&gt;). I initially got confused with this.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fin&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#fin&quot; aria-label=&quot;Anchor link for: fin&quot;&gt;Fin&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Overall, I am very satisfied with WezTerm and have fully switched to using it daily. One cool feature I want to mention is the quick connect to servers in Known hosts via SSH (Command Palette → type server name → Enter OR Nav Bar → Shell → Click on server name). WezTerm also has &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wezfurlong.org&#x2F;wezterm&#x2F;recipes&#x2F;workspaces.html&quot;&gt;Workspaces&lt;&#x2F;a&gt; – an alternative to tmux, but I haven&#x27;t used it actively yet.&lt;&#x2F;p&gt;
&lt;p&gt;Here a &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;vladkens&#x2F;f2ae7c374c1752c4b1581c5e7dffa900&quot;&gt;gist&lt;&#x2F;a&gt; with the final config from this article.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;wezfurlong.org&#x2F;wezterm&#x2F;config&#x2F;files.html&quot;&gt;https:&#x2F;&#x2F;wezfurlong.org&#x2F;wezterm&#x2F;config&#x2F;files.html&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;alexplescan.com&#x2F;posts&#x2F;2024&#x2F;08&#x2F;10&#x2F;wezterm&#x2F;&quot;&gt;https:&#x2F;&#x2F;alexplescan.com&#x2F;posts&#x2F;2024&#x2F;08&#x2F;10&#x2F;wezterm&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>2024 In Review</title>
        <published>2025-01-01T00:00:00+00:00</published>
        <updated>2025-01-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/2024-in-review/"/>
        <id>https://vladkens.cc/2024-in-review/</id>
        
        <content type="html" xml:base="https://vladkens.cc/2024-in-review/">&lt;p&gt;&lt;img src=&quot;&#x2F;2024-review-dalle.webp&quot; alt=&quot;post cover image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I have never written an annual report on my work before, but since I also spend time on open source projects, I decided to write one (maybe it will become a tradition).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;programming-languages-and-tools&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#programming-languages-and-tools&quot; aria-label=&quot;Anchor link for: programming-languages-and-tools&quot;&gt;Programming Languages and Tools&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;rust&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#rust&quot; aria-label=&quot;Anchor link for: rust&quot;&gt;Rust&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;The main change in my work was the active use of Rust in the second half of the past year. I mainly write in Rust where I used to write in Go. Overall, the language is more complex than Go and sometimes confusing with the borrow checker, but in general, it is quite convenient to write – I can&#x27;t say that the speed of writing code significantly decreases compared to other languages – in general, the approaches that need to be used are roughly the same for all languages.&lt;&#x2F;p&gt;
&lt;p&gt;What I like about Rust:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;crates ecosystem – many libraries available and can be installed in one command&lt;&#x2F;li&gt;
&lt;li&gt;single binary file and low memory consumption&lt;&#x2F;li&gt;
&lt;li&gt;ability to write applications of various directions (web-app, tui, gui, parsers, etc.)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;What I don&#x27;t like about Rust:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;slow Docker image builds (&lt;a href=&quot;&#x2F;fast-multi-arch-docker-for-rust&#x2F;&quot;&gt;my solution&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;a large number of sub-dependencies for web projects (any project on axum will contain 200+ dependencies)&lt;&#x2F;li&gt;
&lt;li&gt;use of C-binding in &quot;core&quot; libraries like rust-tls (ring) – complicates cross-compilation because you have to maintain a C toolchain as well (fixed through Zig build, but it looks monstrous)&lt;&#x2F;li&gt;
&lt;li&gt;lack of finished solutions for serde (&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;serde-rs&#x2F;serde&#x2F;issues&#x2F;2254&quot;&gt;default values&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;users.rust-lang.org&#x2F;t&#x2F;serde-how-to-parse-json-partially-7-years-later&#x2F;97030&quot;&gt;partial initialization&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;It&#x27;s nice to write various parsers in Rust, and then they can be coolly parallelized (with &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;rayon&#x2F;latest&#x2F;rayon&#x2F;&quot;&gt;rayon&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;tokio&#x2F;latest&#x2F;tokio&#x2F;fs&#x2F;index.html&quot;&gt;tokio&lt;&#x2F;a&gt;), in Go I had a problems with this due to immutable strings and lack of GC control.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;main-languages&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#main-languages&quot; aria-label=&quot;Anchor link for: main-languages&quot;&gt;Main languages&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;The main languages remained the same: Python, NodeJS&#x2F;TypeScript. I also actively used NextJS on several projects, overall I was satisfied – it&#x27;s faster and easier to write frontends, but it&#x27;s quite difficult to find problem&#x27;s solutions sometimes (many Github issues, often they are open, and the comments contain answers that no longer work).&lt;&#x2F;p&gt;
&lt;p&gt;The main fail of the year in the NodeJS ecosystem is the update of ESLint from 8 -&amp;gt; 9 – completely incompatible API with all existing plugins, the configuration file became larger and more complex – it&#x27;s not clear why the authors made this diversion. I also tried &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;biomejs.dev&quot;&gt;Binome&lt;&#x2F;a&gt; as an alternative to ESLint &#x2F; Prettier, but it&#x27;s completely different and you need to redo a lot, and not everything you need is available at the moment, I continue to monitor this project.&lt;&#x2F;p&gt;
&lt;p&gt;I also tried Zig, but didn&#x27;t write anything serious. Personally, I didn&#x27;t understand why this language is needed. At the time I tried it, there was no even package manager yet. Obviously Zig is a competitor to C (not Rust), but C is now much richer in its toolkit and support in other languages. The only thing I can point out is &lt;code&gt;zig build&lt;&#x2F;code&gt; which can build C projects too and does it with less problems.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;about-llm&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#about-llm&quot; aria-label=&quot;Anchor link for: about-llm&quot;&gt;About LLM&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;I want to separately note about use of GPTs in work. I have an opportunity to do business tasks in the format of parsing and analyzing texts. What a couple of years ago was done with a bunch of regex, etc., can now be done through GPT and it works great! I tried using local Llama2, but it would have taken weeks to process my data on M2 chip. I redo the solution to use ChatGPT API and processed the data in a couple of days. It&#x27;s good that all LLMs support openai-client API in Python, so the code almost didn&#x27;t need to be rewritten. Among the disadvantages of LLama-like aka local running, I also want to note the lack of support for &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;platform.openai.com&#x2F;docs&#x2F;guides&#x2F;function-calling&quot;&gt;Function calling&lt;&#x2F;a&gt; (to guarantee to bring the LLM response to the desired structure, in my case). The last time I did something serious was more than six months ago, maybe a lot has changed. I also tested gemma2, the inference speed was impressive, and the quality of the answers was not much worse.&lt;&#x2F;p&gt;
&lt;p&gt;As local runners, I used &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ggerganov&#x2F;llama.cpp&quot;&gt;llama.cpp&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;vladkens.cc&#x2F;2024-in-review&#x2F;mlx_ml&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;ml-explore&#x2F;mlx&lt;&#x2F;a&gt; – the second one uses Mac resources better (checked through &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&quot;&gt;macmon&lt;&#x2F;a&gt;), but new models come out a bit slower on it. Some people use &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ollama&#x2F;ollama&quot;&gt;ollama&lt;&#x2F;a&gt;, but I didn&#x27;t understand why, considering that it has an incompatible client with openai-client API and slower performance.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;blog&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#blog&quot; aria-label=&quot;Anchor link for: blog&quot;&gt;Blog&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Initially, I ran my blog only on Medium, but it&#x27;s not comfortable to write text there – it&#x27;s much easier to write and edit in the same editor where I write code (plus my editor has Copilot). Therefore, I decided to move my blog to a static page generator. As an engine, I chose &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zola&lt;&#x2F;a&gt; (Rust-based, simple, and fast); I also tried &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;astro.build&#x2F;&quot;&gt;Astro&lt;&#x2F;a&gt;, but it&#x27;s too big and complex for such a simple task. Overall, Zola is good, but it lacks some filters in &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;keats.github.io&#x2F;tera&#x2F;docs&#x2F;&quot;&gt;templating&lt;&#x2F;a&gt;, not enough flexibility in file structure, and not all popular languages are supported in code highlighting.&lt;&#x2F;p&gt;
&lt;p&gt;I left Medium as a fallback for old readers. I also made a cross-post on &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;dev.to&#x2F;vladkens&quot;&gt;dev.to&lt;&#x2F;a&gt;, but there are very few views. Medium is disappointed with the lack of the ability to automate cross-posting (they have a deprecated API, but it does not support updating articles and code highlights). Most likely, it&#x27;s possible to reverse engineer how they save articles through their editor (changes are sent as diffs). Does anyone else need this besides me?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;new-projects&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#new-projects&quot; aria-label=&quot;Anchor link for: new-projects&quot;&gt;New projects&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Last year I launched several new projects (in chronological order):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;timewiz&quot;&gt;timewiz.cc&lt;&#x2F;a&gt; (&lt;code&gt;react&lt;&#x2F;code&gt;, &lt;code&gt;webapp&lt;&#x2F;code&gt;) – a tool to find common working hours for distributed teams (an alternative to worldtimebuddy.com, I don&#x27;t remember exactly why I made my own version). Score: fail.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;ecloop&quot;&gt;ecloop&lt;&#x2F;a&gt; (&lt;code&gt;c&lt;&#x2F;code&gt;, &lt;code&gt;cli&lt;&#x2F;code&gt;) – secp256k1 elliptic curve implementation for Apple chips. Mainly an educational project to understand cryptography, SIMD optimizations, etc. Added several standard use cases for finding Bitcoin keys by brute force, but mathematically this is pointless, so as I said earlier, this is more of an interesting educational project (and I wanted to publish a series of articles on cryptography, but didn&#x27;t have time last year, I hope to do it this year). Some people use this project in hopes of finding something. I also had ideas to add Metal API support – but that takes a lot of time, so I switched to other projects. Score: okay.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&quot;&gt;macmon&lt;&#x2F;a&gt; (&lt;code&gt;rust&lt;&#x2F;code&gt;, &lt;code&gt;tui&lt;&#x2F;code&gt;) – TUI program for monitoring MacOS performance (CPU&#x2F;GPU&#x2F;ANE usage, RAM, temps). My first public Rust project, a lot of reverse engineering of how &lt;a href=&quot;&#x2F;powermetrics-macos&#x2F;&quot;&gt;powermetrics in MacOS&lt;&#x2F;a&gt; works, C-bindings. The project is used both by users in TUI mode and by other projects in headless mode (JSON metrics). Score: success.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;ghstats&quot;&gt;ghstats&lt;&#x2F;a&gt; (&lt;code&gt;rust&lt;&#x2F;code&gt;, &lt;code&gt;axum&lt;&#x2F;code&gt;, &lt;code&gt;htmx&lt;&#x2F;code&gt;, &lt;code&gt;webapp&lt;&#x2F;code&gt;) – a small self-hosted service that collects and saves GitHub repo statistics, has several built-in views and an API to retrieve all statistics. The project started well, but then kind of fizzled out in terms of issues and feature requests, most likely users are satisfied with the current functionality. I would like to add more visualizations, but I haven&#x27;t had time for that yet. The main thing for now is that the statistics are collected and saved, so something can be done with this in the future. Technically, I like that the service consumes only 10 MB of RAM. Score: okay.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;ogp&quot;&gt;ogp&lt;&#x2F;a&gt; (&lt;code&gt;rust&lt;&#x2F;code&gt;, &lt;code&gt;axum&lt;&#x2F;code&gt;, &lt;code&gt;api-service&lt;&#x2F;code&gt;) – a small project for generating &lt;a href=&quot;&#x2F;og-image-generator&#x2F;&quot;&gt;OGP articles preview&lt;&#x2F;a&gt; as a service. Used in this blog (you can check by sending this article to your friends in a messenger or social network 😀). Worked with the SVG standard (I thought it was more adequate) and generating PNG from SVG. Score: more of fail.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;compose-updater&quot;&gt;compose-updater&lt;&#x2F;a&gt; (&lt;code&gt;python&lt;&#x2F;code&gt;, &lt;code&gt;api-service&lt;&#x2F;code&gt;) – a project for updating the version of a docker image from CI in a closed infrastructure. I didn&#x27;t find anything ready to solve this task. There is &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;containrrr&#x2F;watchtower&quot;&gt;watchtower&lt;&#x2F;a&gt;, but it&#x27;s more about keeping up-to-date docker images, rather than updating a specific one, and also I couldn&#x27;t run it with ECR repos – the author made a super minimalist image in which I couldn&#x27;t enter through &lt;code&gt;sh&lt;&#x2F;code&gt; to debug. The second alternative is &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;umputun&#x2F;updater&quot;&gt;umputun&#x2F;updater&lt;&#x2F;a&gt;, but it&#x27;s more about running different shell commands through a webhook. I chose Python because I didn&#x27;t find a Rust crate for Docker API (most likely it exists, I just didn&#x27;t understand which one is really good). Score: – (I didn&#x27;t promote the project anywhere, I use it for my own purposes for now).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;existing-projects&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#existing-projects&quot; aria-label=&quot;Anchor link for: existing-projects&quot;&gt;Existing projects&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;twscrape&quot;&gt;twscrape&lt;&#x2F;a&gt; (&lt;code&gt;python&lt;&#x2F;code&gt;, &lt;code&gt;lib&lt;&#x2F;code&gt;) – a library &lt;a href=&quot;&#x2F;twscrape&#x2F;&quot;&gt;for parsing&lt;&#x2F;a&gt; data from X&#x2F;Twitter. Mainly the project is in maintenance mode, I check its functionality every few months, and there have been no requests for new features.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;apigen-ts&quot;&gt;apigen-ts&lt;&#x2F;a&gt; (&lt;code&gt;typescript&lt;&#x2F;code&gt;, &lt;code&gt;lib&lt;&#x2F;code&gt;) – a library &lt;a href=&quot;&#x2F;simple-typescript-api-client-generator&#x2F;&quot;&gt;for generating&lt;&#x2F;a&gt; TypeScript client OpenAPI spec. I continue to use it in my projects; I also see that there are a small number of other users. My relevance has slightly decreased due to the NextJS&#x2F;TRPC stack, but in other configurations (e.g. FastApi + React), it is still relevant, so use it. Periodically there are requests to fix something or add a feature.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;abandoned-projects&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#abandoned-projects&quot; aria-label=&quot;Anchor link for: abandoned-projects&quot;&gt;Abandoned projects&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I also have several projects that I didn&#x27;t finish and abandoned. I&#x27;ll write about them here, maybe someone needs something from this, then I can return to on it.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;anypost&lt;&#x2F;code&gt; – cross-posting between static blog, Medium, Dev.to, Substack, and collecting joined article statistics. I abandoned the project due to the lack of an API at Medium – the only solution I found was through protocol reverse and session cookie.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;bcloop&lt;&#x2F;code&gt; – a program to walk Bitcoin-like blockchain and compile the final UTXO list. I abandoned it because I couldn&#x27;t figure out how to effectively create a HashMap-like structure with external memory support to run on computers with small RAM (less than 32GB, LOL).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;tg-watcher&lt;&#x2F;code&gt; – a program that listens to all incoming messages in Telegram (chats &amp;amp; channels) and saves their history in a separate database with the ability to search through these messages later. I have the first version that just saves messages in json files, but I didn&#x27;t develop the idea further.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;devices&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#devices&quot; aria-label=&quot;Anchor link for: devices&quot;&gt;Devices&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;m not a big tech geek, but I want to say about a few devices which made my life easier:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;store.mele.cn&#x2F;products&#x2F;mele-quieter-4c-n100-3-4ghz-fanless-mini-computer-lpddr4x-win11-hdmi-4k-wi-fi-5-bt-5-1-usb-3-2-2-usb-2-0-1-type-c-1?variant=43958369648818&quot;&gt;MeLE Fanless Quieter 4C&lt;&#x2F;a&gt; – a small fanless PC for &lt;em&gt;homelab&lt;&#x2F;em&gt;, I use it as a native Linux via SSH for testing various programs and keep some cron jobs on it for data collection. It&#x27;s cool that it&#x27;s silent because it has no fan, but it heats up a lot under load. The performance of the N100 chip surprised me – only 2x slower than M2 chip (tested with &lt;code&gt;ecloop bench&lt;&#x2F;code&gt;, single core).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;promate.net&#x2F;products&#x2F;hdmi-pd100&quot;&gt;Promate HDMI-PD100&lt;&#x2F;a&gt; – nice cable format to connect a monitor and my Mac. One cable is needed to charge and transmit the video stream. Before that, I used hubs, but it&#x27;s a big block. I&#x27;m glad I see fewer wires.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;at-glance&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#at-glance&quot; aria-label=&quot;Anchor link for: at-glance&quot;&gt;At Glance&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Over the year, 8 articles were published, totaling 9039 words (~45 minutes to read), and gained 5203 views. Top 3 articles:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;&#x2F;htmx-table-sorting&#x2F;&quot;&gt;Table sorting and pagination with HTMX&lt;&#x2F;a&gt; – 1714 views&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;&#x2F;macmon&#x2F;&quot;&gt;macmon – Mac Usage Monitor in Terminal&lt;&#x2F;a&gt; – 953 views&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;&#x2F;aws-wireguard-vpn-terraform&#x2F;&quot;&gt;Setting up WireGuard VPN at AWS with Terraform&lt;&#x2F;a&gt; – 642 views&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;em&gt;Data aggregated from this site (with &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;umami.is&#x2F;&quot;&gt;umami&lt;&#x2F;a&gt;), Medium, and Dev.to. &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;blog&#x2F;blob&#x2F;main&#x2F;_stats_at_glance.py&quot;&gt;Script&lt;&#x2F;a&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Public GitHub projects – totaling 312 commits, 49 issues closed, 43 releases created, and 1394 stars gained. Top-3 repos:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;twscrape&quot;&gt;twscrape&lt;&#x2F;a&gt; – +802 stars &#x2F; +52515 views&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&quot;&gt;macmon&lt;&#x2F;a&gt; – +420 stars &#x2F; +6899 views&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;ghstats&quot;&gt;ghstats&lt;&#x2F;a&gt; – +128 stars &#x2F; +2757 views&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;em&gt;Data aggregated with &lt;code&gt;ghstats&lt;&#x2F;code&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I hope I will see a different top with new projects this year 😀&lt;&#x2F;p&gt;
&lt;h2 id=&quot;donations&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#donations&quot; aria-label=&quot;Anchor link for: donations&quot;&gt;Donations&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In &lt;code&gt;twscrape&lt;&#x2F;code&gt; repository I was asked to make it possible to send coffee as donations. Over the year I received 38 cups of coffee from 10 people. I spend these coffees on an annual &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.parallels.com&#x2F;&quot;&gt;Parallels&lt;&#x2F;a&gt; subscription, which allows me to test some apps on Windows. Also, I partially paid from this fund for MeLE and VPS, which I used to test apps as well. Many thanks for supporting my work!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Creating OG Images for Static Pages with Rust</title>
        <published>2024-11-30T00:00:00+00:00</published>
        <updated>2024-11-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/og-image-generator/"/>
        <id>https://vladkens.cc/og-image-generator/</id>
        
        <content type="html" xml:base="https://vladkens.cc/og-image-generator/">&lt;p&gt;OGP (&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ogp.me&#x2F;&quot;&gt;Open Graph Protocol&lt;&#x2F;a&gt;) is an HTML meta-tags specification for websites to make links look nice in third-party services such as Facebook, X, LinkedIn or chat apps. OGP also allows to specify a link to page thumbnail that will be shown as preview when link shared, which can increase clickability.&lt;&#x2F;p&gt;
&lt;p&gt;Some blog engines have built-in functions for this. I use &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;getzola.org&#x2F;&quot;&gt;Zola&lt;&#x2F;a&gt; (static page generator) to create pages for this blog. Unfortunately, Zola does not have an ability to generate OG images. This can be achieved with external tools or scripts during the build process. Another approach to use edge functions (such as &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vercel.com&#x2F;docs&#x2F;functions&#x2F;og-image-generation&quot;&gt;vercel&#x2F;og&lt;&#x2F;a&gt;) to generate thumbnails on the fly. However, this approach relies on a specific service provider, which I want to avoid.&lt;&#x2F;p&gt;
&lt;p&gt;I thought, why not use OG image generation as a service? I searched around and found &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sagarhani&#x2F;og-image-generator&quot;&gt;og-image-generator&lt;&#x2F;a&gt; by sagarhani.&lt;&#x2F;p&gt;
&lt;p&gt;The functionality of &lt;code&gt;og-image-generator&lt;&#x2F;code&gt; worked well for me, and I used it for this blog for some time. However, the project seems abandoned, and I&#x27;m unsure how the author feels about additional load on their service. I decided it shouldn&#x27;t be too hard to create a similar service myself — a single endpoint for generating images with search params. Moreover, when I looked into the source code of &lt;code&gt;og-image-generator&lt;&#x2F;code&gt;, I noticed that it launches Chrome to render an image from HTML, which felt like significant overhead to me.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;coding&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#coding&quot; aria-label=&quot;Anchor link for: coding&quot;&gt;Coding&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I need an endpoint that accepts: article title, URL&#x2F;domain, author name and avatar via search parameters. Lately, I&#x27;ve been using Rust for most of my pet projects, so I decided to build this service with Rust as well. I added a route in &lt;code&gt;axum&lt;&#x2F;code&gt; and implemented a handler that generates SVG images, using some basic math to calculate the positioning of elements. The size of the OG image is predefined as &lt;code&gt;1200x630&lt;&#x2F;code&gt;, following the specefication. SVG allows the use of a &lt;code&gt;&amp;lt;style&amp;gt;&lt;&#x2F;code&gt; tag, making it easy to customise default font-family.&lt;&#x2F;p&gt;
&lt;p&gt;The only challenge I encountered was creating a mask for the image. I initially thought SVG might have some syntactic sugar for this, but it essentially works the same way as masks in Photoshop.&lt;&#x2F;p&gt;
&lt;p&gt;Example of SVG generation (&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;maud.lambda.xyz&#x2F;&quot;&gt;&lt;code&gt;maud&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; is an HTML template engine on Rust macros):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;maud::{html, Markup};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;render_svg&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;title&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;author&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;photo&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Markup {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;(w, h) = (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1200&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;630&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; pic_r = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;50&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; pic_y = h - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;128&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; l1y = pic_y - (pic_r - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;) &#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;48 &lt;&#x2F;span&gt;&lt;span&gt;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span&gt;- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; l2y = pic_y - (pic_r - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;) &#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;32 &lt;&#x2F;span&gt;&lt;span&gt;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;6 &lt;&#x2F;span&gt;&lt;span&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;32&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  html!(svg xmlns=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; viewBox=(format!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0 0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{} {}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, w, h)) width=(w) height=(h) {
&lt;&#x2F;span&gt;&lt;span&gt;    style { (&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;text { font-family: &amp;#39;Open Sans&amp;#39;, Arial, sans-serif; }&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; ) }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    rect x=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; y=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; width=(w) height=(h) fill=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;black&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; stroke=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;white&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; stroke-width=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {}
&lt;&#x2F;span&gt;&lt;span&gt;    text x=(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;120&lt;&#x2F;span&gt;&lt;span&gt;) y=(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;) font-weight=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;700&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; font-size=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;72&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; fill=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;white&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; { (title) }
&lt;&#x2F;span&gt;&lt;span&gt;    text x=(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;) y=(l1y) font-weight=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;700&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; font-size=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;48&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; fill=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;white&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; { (author) }
&lt;&#x2F;span&gt;&lt;span&gt;    text x=(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;) y=(l2y) font-weight=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;400&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; font-size=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;32&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; fill=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;white&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; { (url) }
&lt;&#x2F;span&gt;&lt;span&gt;    (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;circle_avatar&lt;&#x2F;span&gt;&lt;span&gt;(photo, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;128&lt;&#x2F;span&gt;&lt;span&gt;, pic_y, pic_r))
&lt;&#x2F;span&gt;&lt;span&gt;  })
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;circle_avatar&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cx&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cy&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;radius&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Markup {
&lt;&#x2F;span&gt;&lt;span&gt;  html!({
&lt;&#x2F;span&gt;&lt;span&gt;    defs {
&lt;&#x2F;span&gt;&lt;span&gt;      clipPath id=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;circle-photo&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; { circle cx=(cx) cy=(cy) r=(radius) {} }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    g clip-path=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;url(#circle-photo)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;      image href=(url) x=(cx-radius) y=(cy-radius) width=(radius * &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;) height=(radius * &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;) {}
&lt;&#x2F;span&gt;&lt;span&gt;      circle cx=(cx) cy=(cy) r=(radius) stroke=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;white&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; stroke-width=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; fill=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;none&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {}
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  })
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And then the SVG image is generated in the Axum handler:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;axum::extract::{Query, Request};
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;axum::http::{header, StatusCode};
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;axum::response::IntoResponse;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::collections::HashMap;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;svg_handler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;req&lt;&#x2F;span&gt;&lt;span&gt;: Request) -&amp;gt; Res&amp;lt;impl IntoResponse&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; qs: Query&amp;lt;HashMap&amp;lt;String, String&amp;gt;&amp;gt; = Query::try_from_uri(req.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;uri&lt;&#x2F;span&gt;&lt;span&gt;())?;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; title = qs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;title&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cloned&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;This is default article title&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; author = qs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;author&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cloned&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Author&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; url = qs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cloned&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;example.com&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; photo = qs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;photo&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cloned&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;gravatar.com&#x2F;avatar&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; svg = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;render_svg&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;title, &amp;amp;author, &amp;amp;url, &amp;amp;photo);
&lt;&#x2F;span&gt;&lt;span&gt;  Ok((StatusCode::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;OK&lt;&#x2F;span&gt;&lt;span&gt;, [(header::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;CONTENT_TYPE&lt;&#x2F;span&gt;&lt;span&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;image&#x2F;svg+xml&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)], svg))
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This code will generate the following SVG:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; viewBox=&quot;0 0 1200 630&quot;&gt;&lt;style&gt;text { font-family: &#x27;Open Sans&#x27;, Arial, sans-serif; }&lt;&#x2F;style&gt;&lt;rect x=&quot;0&quot; y=&quot;0&quot; width=&quot;1200&quot; height=&quot;630&quot; fill=&quot;black&quot; stroke=&quot;white&quot; stroke-width=&quot;16&quot;&gt;&lt;&#x2F;rect&gt;&lt;text x=&quot;120&quot; y=&quot;200&quot; font-weight=&quot;700&quot; font-size=&quot;72&quot; fill=&quot;white&quot;&gt;This is default article title&lt;&#x2F;text&gt;&lt;text x=&quot;200&quot; y=&quot;500&quot; font-weight=&quot;700&quot; font-size=&quot;48&quot; fill=&quot;white&quot;&gt;Author&lt;&#x2F;text&gt;&lt;text x=&quot;200&quot; y=&quot;536&quot; font-weight=&quot;400&quot; font-size=&quot;32&quot; fill=&quot;white&quot;&gt;https:&#x2F;&#x2F;example.com&lt;&#x2F;text&gt;&lt;defs&gt;&lt;clipPath id=&quot;circle-photo&quot;&gt;&lt;circle cx=&quot;128&quot; cy=&quot;502&quot; r=&quot;50&quot;&gt;&lt;&#x2F;circle&gt;&lt;&#x2F;clipPath&gt;&lt;&#x2F;defs&gt;&lt;g clip-path=&quot;url(#circle-photo)&quot;&gt;&lt;image href=&quot;https:&#x2F;&#x2F;gravatar.com&#x2F;avatar&#x2F;&quot; x=&quot;78&quot; y=&quot;452&quot; width=&quot;100&quot; height=&quot;100&quot;&gt;&lt;&#x2F;image&gt;&lt;circle cx=&quot;128&quot; cy=&quot;502&quot; r=&quot;50&quot; stroke=&quot;white&quot; stroke-width=&quot;4&quot; fill=&quot;none&quot;&gt;&lt;&#x2F;circle&gt;&lt;&#x2F;g&gt;&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The endpoint can accept &lt;code&gt;title&lt;&#x2F;code&gt;, &lt;code&gt;author&lt;&#x2F;code&gt;, &lt;code&gt;url&lt;&#x2F;code&gt; and &lt;code&gt;photo&lt;&#x2F;code&gt; in the search params, and these values will be passed to SVG template. That&#x27;s pretty much it, I thought, deployed the service to &lt;a href=&quot;&#x2F;deploy-fastapi-with-sqlite-on-flyio&#x2F;&quot;&gt;fly.io&lt;&#x2F;a&gt;, updated the blog links, went to check how new preview looked, and the thumbnail didn&#x27;t display.&lt;&#x2F;p&gt;
&lt;p&gt;It turned out that OG images cannot be SVG (which makes sense, because then different mobile clients would need to be able to render it, which is harder then showing prepared image).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;svg-to-png&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#svg-to-png&quot; aria-label=&quot;Anchor link for: svg-to-png&quot;&gt;SVG to PNG&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;It&#x27;s not a big deal, I thought. A lot things has already been rewritten in Rust, and there&#x27;s probably a ready to use solution for SVG rendering, especially since I found several popular crates for this. But it turned out to be more complicated than expected. Rendering SVG to PNG is quite a complex task, and the SVG specification is huge, so libs not fully implement the specification. However, I only need basic SVG support. I tried several crates and settled on &lt;code&gt;resvg&lt;&#x2F;code&gt;. I wrote a rendering function:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;resvg::{tiny_skia, usvg};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;render_png&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;svg&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Vec&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; tree = {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; opt = usvg::Options::default();
&lt;&#x2F;span&gt;&lt;span&gt;    opt.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;fontdb_mut&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;load_system_fonts&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    usvg::Tree::from_str(svg, &amp;amp;opt).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; size = tree.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;size&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_int_size&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; pixmap = tiny_skia::Pixmap::new(size.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;width&lt;&#x2F;span&gt;&lt;span&gt;(), size.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;height&lt;&#x2F;span&gt;&lt;span&gt;()).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;  resvg::render(&amp;amp;tree, tiny_skia::Transform::default(), &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; pixmap.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;as_mut&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;  pixmap.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;encode_png&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And updated handlers:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; in some reason axum not allow to pass Request as ref – code will not compile, so req.uri() used
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;prepare_svg&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;uri&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;axum::http::Uri) -&amp;gt; Res&amp;lt;String&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; qs: Query&amp;lt;HashMap&amp;lt;String, String&amp;gt;&amp;gt; = Query::try_from_uri(uri)?;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; title = qs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;title&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cloned&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;This is default article title&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; author = qs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;author&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cloned&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Author&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; url = qs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cloned&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;example.com&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; photo = qs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;photo&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cloned&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;gravatar.com&#x2F;avatar&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;  Ok(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;render_svg&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;title, &amp;amp;author, &amp;amp;url, &amp;amp;photo).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_string&lt;&#x2F;span&gt;&lt;span&gt;())
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;svg_handler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;req&lt;&#x2F;span&gt;&lt;span&gt;: Request) -&amp;gt; Res&amp;lt;impl IntoResponse&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; svg = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;prepare_svg&lt;&#x2F;span&gt;&lt;span&gt;(req.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;uri&lt;&#x2F;span&gt;&lt;span&gt;()).await?;
&lt;&#x2F;span&gt;&lt;span&gt;  Ok((StatusCode::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;OK&lt;&#x2F;span&gt;&lt;span&gt;, [(header::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;CONTENT_TYPE&lt;&#x2F;span&gt;&lt;span&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;image&#x2F;svg+xml&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)], svg))
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;png_handler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;req&lt;&#x2F;span&gt;&lt;span&gt;: Request) -&amp;gt; Res&amp;lt;impl IntoResponse&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; svg = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;prepare_svg&lt;&#x2F;span&gt;&lt;span&gt;(req.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;uri&lt;&#x2F;span&gt;&lt;span&gt;()).await?;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; png = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;render_png&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;svg);
&lt;&#x2F;span&gt;&lt;span&gt;  Ok((StatusCode::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;OK&lt;&#x2F;span&gt;&lt;span&gt;, [(header::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;CONTENT_TYPE&lt;&#x2F;span&gt;&lt;span&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;image&#x2F;png&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)], png))
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I run it, and generally, everything works, but the avatar doesn&#x27;t show up.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;ogi-image-generator-1.png&quot; &#x2F;&gt;
&lt;h2 id=&quot;loading-remote-images&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#loading-remote-images&quot; aria-label=&quot;Anchor link for: loading-remote-images&quot;&gt;Loading remote images&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;resvg&lt;&#x2F;code&gt; itself cannot load images from remote URLs used in SVG, but it can render images from a base64-encoded data string. Okay, I&#x27;ll load the image and convert it myself:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;base64::Engine;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;reqwest::header::{HeaderMap, HeaderValue};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;load_base64_image&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Res&amp;lt;String&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; ua = format!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, env!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CARGO_PKG_NAME&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;), env!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CARGO_PKG_VERSION&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;));
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; headers = HeaderMap::new();
&lt;&#x2F;span&gt;&lt;span&gt;  headers.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;insert&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;User-Agent&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, HeaderValue::from_str(&amp;amp;ua)?);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; client = reqwest::Client::builder()
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;default_headers&lt;&#x2F;span&gt;&lt;span&gt;(headers)
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;read_timeout&lt;&#x2F;span&gt;&lt;span&gt;(std::time::Duration::from_secs(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;()?;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; rep = client.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(url).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;send&lt;&#x2F;span&gt;&lt;span&gt;().await?;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; max_size = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1024 &lt;&#x2F;span&gt;&lt;span&gt;* &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1024 &lt;&#x2F;span&gt;&lt;span&gt;* &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; 5MB
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; rep.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;content_length&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    None =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;AppError::new(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Image size is unknown&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;),
&lt;&#x2F;span&gt;&lt;span&gt;    Some(len) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; len &amp;gt; max_size =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;AppError::new(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Image is too large&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;),
&lt;&#x2F;span&gt;&lt;span&gt;    _ =&amp;gt; {}
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; allowed = [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;image&#x2F;jpeg&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;image&#x2F;png&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;image&#x2F;webp&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;image&#x2F;svg+xml&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;];
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; mime = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; rep.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;headers&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(header::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;CONTENT_TYPE&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    None =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;AppError::new(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Content type is unknown&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;),
&lt;&#x2F;span&gt;&lt;span&gt;    Some(ct) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;!allowed.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;contains&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;ct.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_str&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;()) =&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;AppError::new(&amp;amp;format!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Content type is not allowed: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{:?}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, ct))
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    Some(ct) =&amp;gt; ct.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_str&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; rep = rep.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;bytes&lt;&#x2F;span&gt;&lt;span&gt;().await?;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; rep = base64::engine::general_purpose::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;STANDARD&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;encode&lt;&#x2F;span&gt;&lt;span&gt;(rep);
&lt;&#x2F;span&gt;&lt;span&gt;  Ok(format!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;data:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{mime}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;;base64,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{rep}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;))
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;prepare_svg&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;uri&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;axum::http::Uri) -&amp;gt; Res&amp;lt;String&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; photo = qs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;photo&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cloned&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;gravatar.com&#x2F;avatar&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; photo = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;load_base64_image&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;photo).await?;
&lt;&#x2F;span&gt;&lt;span&gt;  Ok(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;render_svg&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;title, &amp;amp;author, &amp;amp;url, &amp;amp;photo).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_string&lt;&#x2F;span&gt;&lt;span&gt;())
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I check generation again – everything is fine, the avatar is present in the final render:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;ogi-image-generator-2.png&quot; &#x2F;&gt;
&lt;h2 id=&quot;docker-image&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#docker-image&quot; aria-label=&quot;Anchor link for: docker-image&quot;&gt;Docker image&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;So, the service is ready. Now, just needed to pack code into a &lt;a href=&quot;&#x2F;fast-multi-arch-docker-for-rust&#x2F;&quot;&gt;Docker image&lt;&#x2F;a&gt;. It&#x27;s pretty much the same as usual, except that fonts files should be added to image too. I usually use Alpine images, and fonts can be added via &lt;code&gt;apk&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;Dockerfile&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-Dockerfile &quot;&gt;&lt;code class=&quot;language-Dockerfile&quot; data-lang=&quot;Dockerfile&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; alpine:latest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;apk add --no-cache ttf-opensans
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# ... copy and run bin file
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;fin&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#fin&quot; aria-label=&quot;Anchor link for: fin&quot;&gt;Fin&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I added a template and copied themes from &lt;code&gt;sagarhani&#x2F;og-image-generator&lt;&#x2F;code&gt;. I also created a preview page where you can experiment with the generation. This is enough for my current needs, but if anyone needs more, Issues&#x2F;PRs are welcome.&lt;&#x2F;p&gt;
&lt;p&gt;The service is available at: &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ogp.fly.dev&quot;&gt;https:&#x2F;&#x2F;ogp.fly.dev&lt;&#x2F;a&gt;&lt;br &#x2F;&gt;
The code is on GitHub: &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;ogp&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;ogp&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The service is currently running without any restrictions. There is also the option to run self-hosted version with &lt;code&gt;ghcr.io&#x2F;vladkens&#x2F;ogp&lt;&#x2F;code&gt; image.&lt;&#x2F;p&gt;
&lt;p&gt;To integrate this service into a static website, you just need to add corresponding &lt;code&gt;&amp;lt;meta&amp;gt;&lt;&#x2F;code&gt; tags with service link and replace token with your data.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;html&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-html &quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;meta
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;property&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;og:image&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;content&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;ogp.fly.dev&#x2F;v0&#x2F;png?title={title}&amp;amp;author={author}&amp;amp;photo={photo}&amp;amp;url={url}&amp;amp;theme={theme}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Usage example for this blog: &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;blog&#x2F;blob&#x2F;ae18520&#x2F;templates&#x2F;base.html#L21&quot;&gt;link generation&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;blog&#x2F;blob&#x2F;ae18520&#x2F;templates&#x2F;base.html#L44&quot;&gt;meta tags&lt;&#x2F;a&gt;. To see link sharing at work click on links below ⬇️💀&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Deploy FastAPI application with SQLite on Fly.io</title>
        <published>2024-10-21T00:00:00+00:00</published>
        <updated>2024-10-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/deploy-fastapi-with-sqlite-on-flyio/"/>
        <id>https://vladkens.cc/deploy-fastapi-with-sqlite-on-flyio/</id>
        
        <content type="html" xml:base="https://vladkens.cc/deploy-fastapi-with-sqlite-on-flyio/">&lt;p&gt;&lt;img src=&quot;&#x2F;sqlite-flyio.png&quot; alt=&quot;post cover image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Cloud solutions are good for medium and large projects, but too heavy for small personal projects. If you want to launch something small (a few api endpoins and a small repository), there are three options:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Use the same approaches as for &quot;big&quot; projects (AWS ECS&#x2F;EKS, RDS), but they are redundant, and infrastructure code can be larger than code of the actual project. Also it&#x27;s expensive (~$100).&lt;&#x2F;li&gt;
&lt;li&gt;Use serverless solutions (Lambda, Vercel). Most cloud providers have such solutions, but these services have difficulties with simple databases – they provide cheap vendor solutions (AWS) or require a managed database, which again is expensive (mostly nothing for serverless, ~$20 for DB)&lt;&#x2F;li&gt;
&lt;li&gt;Use VPS with Docker. It is cheap (~$5 for small machine) and almost no need to manage infrastructure, but deployments sucks (needs private or self-hosted registry, SSH access from CI).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I usually write my small applications using SQLite, it&#x27;s a handy little single file database that works in any programming language and can be copied to local machine to analyze data for example. So I was looking for some middleware solution that combines the serveless approach, ease of deployment and ability to use SQLite and found Fly.io.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;setup&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#setup&quot; aria-label=&quot;Anchor link for: setup&quot;&gt;Setup&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;If you don&#x27;t have an account in Fly.io – you need to &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;fly.io&#x2F;app&#x2F;sign-up&quot;&gt;create&lt;&#x2F;a&gt; it. Also &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;fly.io&#x2F;docs&#x2F;flyctl&#x2F;install&#x2F;&quot;&gt;CLI tool&lt;&#x2F;a&gt; called &lt;code&gt;flyctl&lt;&#x2F;code&gt; required to manage projects. Fly.io can be deployed both locally and from CI.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;flyctl&lt;&#x2F;code&gt; makes deploy from project&#x27;s root folder from Dockerfile, which is cool, because same Dockerfile can be used in other systems. For play with Fly.io, I prepared a simple FastAPI project that stores state in database – generic url shortener with click counting.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;Dockerfile&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;Dockerfile&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-Dockerfile &quot;&gt;&lt;code class=&quot;language-Dockerfile&quot; data-lang=&quot;Dockerfile&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; python:3.13-alpine
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; .&#x2F;requirements.txt .
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;pip install --no-cache-dir --upgrade -r requirements.txt
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; . &#x2F;app
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ENV &lt;&#x2F;span&gt;&lt;span&gt;HOST=0.0.0.0 PORT=8080
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;EXPOSE &lt;&#x2F;span&gt;&lt;span&gt;${PORT}
&lt;&#x2F;span&gt;&lt;span&gt;CMD uvicorn main:app --host ${HOST} --port ${PORT}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;main.py&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;asyncio
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;random
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;string
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;urllib.parse &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;urlparse
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;aiosqlite
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;fastapi &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;FastAPI, HTTPException, Request
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;fastapi.responses &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;RedirectResponse
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;DB_PATH &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;data&#x2F;app.db&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;app = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;FastAPI&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;async def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get_db&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; aiosqlite.Connection:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;db := &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;getattr&lt;&#x2F;span&gt;&lt;span&gt;(get_db, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;_db&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;db.is_alive:
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;db
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    db = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span&gt;aiosqlite.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;connect&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;DB_PATH&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;loop&lt;&#x2F;span&gt;&lt;span&gt;=asyncio.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;get_event_loop&lt;&#x2F;span&gt;&lt;span&gt;())
&lt;&#x2F;span&gt;&lt;span&gt;    db.row_factory = aiosqlite.Row
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    qs = &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;CREATE TABLE &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;IF NOT EXISTS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;links&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; (
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;        created_at &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;INTEGER DEFAULT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; (strftime(&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;now&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;)),
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;        short_code &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;TEXT PRIMARY KEY&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;        full_url &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;TEXT &lt;&#x2F;span&gt;&lt;span&gt;NOT &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;        clicks &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;INTEGER DEFAULT &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    )
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span&gt;db.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;execute&lt;&#x2F;span&gt;&lt;span&gt;(qs)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span&gt;db.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;commit&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;setattr&lt;&#x2F;span&gt;&lt;span&gt;(get_db, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;_db&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, db)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;db
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;random_code&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;length&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; str:
&lt;&#x2F;span&gt;&lt;span&gt;    alphabet = string.ascii_letters + string.digits
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;join&lt;&#x2F;span&gt;&lt;span&gt;(random.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;choice&lt;&#x2F;span&gt;&lt;span&gt;(alphabet) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;range&lt;&#x2F;span&gt;&lt;span&gt;(length))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;is_valid_url&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;: str) -&amp;gt; bool:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;try&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        parts = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;urlparse&lt;&#x2F;span&gt;&lt;span&gt;(url)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;all&lt;&#x2F;span&gt;&lt;span&gt;([parts.scheme, parts.netloc])
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;except &lt;&#x2F;span&gt;&lt;span&gt;ValueError:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;False
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@app.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;post&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;async def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;shorten&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;: str, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;req&lt;&#x2F;span&gt;&lt;span&gt;: Request):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;not &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;is_valid_url&lt;&#x2F;span&gt;&lt;span&gt;(url):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;raise &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;HTTPException&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;status_code&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;400&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;detail&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Invalid URL&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    host = req.headers.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;host&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;host is &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;raise &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;HTTPException&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;status_code&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;500&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;detail&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Missing host header&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    short_code = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;random_code&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;    db = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;get_db&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;    qs = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;INSERT INTO&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; links (short_code, full_url) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;VALUES&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; (?, ?)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span&gt;db.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;execute&lt;&#x2F;span&gt;&lt;span&gt;(qs, (short_code, url))
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span&gt;db.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;commit&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return f&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;{host}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;{short_code}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@app.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;async def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;list_links&lt;&#x2F;span&gt;&lt;span&gt;():
&lt;&#x2F;span&gt;&lt;span&gt;    db = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;get_db&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;    qs = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;SELECT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; short_code, full_url, clicks &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; links &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ORDER BY&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; created_at &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;DESC&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;async with &lt;&#x2F;span&gt;&lt;span&gt;db.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;execute&lt;&#x2F;span&gt;&lt;span&gt;(qs) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;cursor:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return await &lt;&#x2F;span&gt;&lt;span&gt;cursor.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;fetchall&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@app.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{short_code}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;async def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;redirect&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;short_code&lt;&#x2F;span&gt;&lt;span&gt;: str):
&lt;&#x2F;span&gt;&lt;span&gt;    db = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;get_db&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;    qs = &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;UPDATE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; links &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;SET&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; clicks &lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; clicks &lt;&#x2F;span&gt;&lt;span&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;WHERE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; short_code &lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; ?
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    RETURNING full_url
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;async with &lt;&#x2F;span&gt;&lt;span&gt;db.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;execute&lt;&#x2F;span&gt;&lt;span&gt;(qs, (short_code,)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;cursor:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;row := &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span&gt;cursor.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;fetchone&lt;&#x2F;span&gt;&lt;span&gt;():
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;RedirectResponse&lt;&#x2F;span&gt;&lt;span&gt;(row[&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;full_url&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;])
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;raise &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;HTTPException&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;status_code&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;404&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;requirements.txt&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;aiosqlite
&lt;&#x2F;span&gt;&lt;span&gt;fastapi
&lt;&#x2F;span&gt;&lt;span&gt;uvicorn
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;deploy&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#deploy&quot; aria-label=&quot;Anchor link for: deploy&quot;&gt;Deploy&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;To deploy our code, first we need to create a Fly.io project. This can be done either in the web interface or with &lt;code&gt;flyctl&lt;&#x2F;code&gt;. To create proejct with CLU tool in root folder (where code located) flyctl launch should be runned. This command will offer to select desired hardware and will create &lt;code&gt;fly.toml&lt;&#x2F;code&gt; file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;fly&lt;&#x2F;span&gt;&lt;span&gt; launch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --build-only
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can modify project in future by changing parameters in this file or via web ui. The basic &lt;code&gt;fly.toml&lt;&#x2F;code&gt; looks fine, but SQLite requires Storage, which can be created with:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;fly&lt;&#x2F;span&gt;&lt;span&gt; volumes create sqlite_data&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -s&lt;&#x2F;span&gt;&lt;span&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -r&lt;&#x2F;span&gt;&lt;span&gt; ams
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;where &lt;code&gt;-s 1&lt;&#x2F;code&gt; sets volume size to 1 GB (default is 3 GB), and &lt;code&gt;-r&lt;&#x2F;code&gt; is region in which volume will be created (use same region in which Fly.io project is created). You can always change storage size later.&lt;&#x2F;p&gt;
&lt;p&gt;The last thing to do is to add a &lt;code&gt;mounts&lt;&#x2F;code&gt; section to &lt;code&gt;fly.toml&lt;&#x2F;code&gt;, which attaches the volume to the application:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;toml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-toml &quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;&lt;span&gt;[mounts]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;source &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sqlite_data&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;destination &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;data&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;sqlite_data&lt;&#x2F;code&gt; is the name of the storage, &lt;code&gt;&#x2F;data&lt;&#x2F;code&gt; is the path where volume will be connected. This is essentially same as &lt;code&gt;docker run --mount source=sqlite_data,target=&#x2F;data&lt;&#x2F;code&gt; or corresponding Docker Compose section.&lt;&#x2F;p&gt;
&lt;p&gt;SQLite cannot be writable from more than one app, and Fly.io by default creates 2 instances for an app, so we can specify the number of replicas as one just in case:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;fly&lt;&#x2F;span&gt;&lt;span&gt; scale count 1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;All configurations are done now and we can deploy our app with command:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;fly&lt;&#x2F;span&gt;&lt;span&gt; deploy
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The app should boot successfully and the public DNS name will be printed to console. Now we can check it out by posting some url to shortener:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; curl&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -X&lt;&#x2F;span&gt;&lt;span&gt; POST &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;fly-fastapi-sqlite.fly.dev&#x2F;?url=https:&#x2F;&#x2F;example.com&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;https:&#x2F;&#x2F;fly-fastapi-sqlite.fly.dev&#x2F;8ydmfAcK
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then we can visit this link, it should redirect to &lt;code&gt;https:&#x2F;&#x2F;example.com&lt;&#x2F;code&gt;. Finally, we can check that clicks are updated:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; curl&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -s &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;fly-fastapi-sqlite.fly.dev&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;jq
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;  {
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;short_code&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;8ydmfAcK&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;full_url&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;example.com&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;clicks&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; 1
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To check that database state saved between deployments, we can perform new deployment with &lt;code&gt;fly deploy&lt;&#x2F;code&gt; and check that links list remained same as above (1 link, 1 click).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;migrations&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#migrations&quot; aria-label=&quot;Anchor link for: migrations&quot;&gt;Migrations&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;If you are using an external solution for migrations, rather than running them from code when app starts, then only way to run migration is to put it in Dockerfile as part of the RUN command.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;backup&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#backup&quot; aria-label=&quot;Anchor link for: backup&quot;&gt;Backup&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;We can connect to machine with &lt;code&gt;fly ssh console&lt;&#x2F;code&gt; and then in &lt;code&gt;&#x2F;data&lt;&#x2F;code&gt; folder interact with database file. Also we can copy database file to local machine with:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;fly&lt;&#x2F;span&gt;&lt;span&gt; ssh sftp get &#x2F;data&#x2F;app.db .&#x2F;app-backup.db
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot;&gt;Conclusion&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Fly.io is a simple and convenient service for deploying applications. Deploy works from Docker Containers, additional services include PSQL, Redis, S3 like storage (unlike Vercel). It&#x27;s cheap, the cheapest service costs 3 dollars (1 shared CPU &#x2F; 256 MB) – maybe even less, if you have little traffic – container shuts down after a few minutes without activity and automatically turns on when traffic appears.&lt;&#x2F;p&gt;
&lt;p&gt;On downside, there is no built-in solution for scheduled tasks – instead, the official solution is to set up a separate server with &lt;code&gt;crontab&lt;&#x2F;code&gt; and run tasks from it – it&#x27;s kind of creepy.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;fly.io&#x2F;docs&#x2F;rails&#x2F;advanced-guides&#x2F;sqlite3&#x2F;&quot;&gt;https:&#x2F;&#x2F;fly.io&#x2F;docs&#x2F;rails&#x2F;advanced-guides&#x2F;sqlite3&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;matthewsetter.com&#x2F;deploy-go-sqlite-app-flydotapp&#x2F;&quot;&gt;https:&#x2F;&#x2F;matthewsetter.com&#x2F;deploy-go-sqlite-app-flydotapp&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;programmingmylife.com&#x2F;2023-11-06-using-sqlite-for-a-django-application-on-flyio.html&quot;&gt;https:&#x2F;&#x2F;programmingmylife.com&#x2F;2023-11-06-using-sqlite-for-a-django-application-on-flyio.html&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Setting up WireGuard VPN at AWS with Terraform</title>
        <published>2024-10-08T00:00:00+00:00</published>
        <updated>2024-10-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/aws-wireguard-vpn-terraform/"/>
        <id>https://vladkens.cc/aws-wireguard-vpn-terraform/</id>
        
        <content type="html" xml:base="https://vladkens.cc/aws-wireguard-vpn-terraform/">&lt;p&gt;All resources in AWS work inside private VPC. Sometimes you may need to access these resources from local computer (e.g. to interact with database). Some resources, like RDS, have the option to enable public access to them – but this is unsecure. Of course you can configure Security Group to allow access to public resource only from allowed IPs to make this setup a bit better, but still in this case all your colleagues must to have static IPs, which is not always true.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;objective&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#objective&quot; aria-label=&quot;Anchor link for: objective&quot;&gt;Objective&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;We need to provide a quick and easy solution to give access to internal AWS VPC resources for our team. In general, there are two ways to do this:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Bastion &#x2F; Jump Host – EC2 instance with SSH access for each member&lt;&#x2F;li&gt;
&lt;li&gt;Private VPN – EC2 instance with VPN config for each member&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;In both cases we need to to setup a custom EC2 instance, so second variant seems more convenient to me.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;preparation&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#preparation&quot; aria-label=&quot;Anchor link for: preparation&quot;&gt;Preparation&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In addition to the traditional Terraform client, we will need WireGuard CLI tools to generate a key pair. You can install WireGuard tools on macOS via &lt;code&gt;brew&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span&gt; install wireguard-tools
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;initial-terraform&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#initial-terraform&quot; aria-label=&quot;Anchor link for: initial-terraform&quot;&gt;Initial Terraform&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;First, as usual, we need to configure Terraform Provider and get VPC and Public Subnet data where we want to host our VPN server. On this step you can export VPC &#x2F; Public Subnet from another layer or pass them via variables. I will access my VPC and Public Subnet by name.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span&gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  required_providers {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;aws &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;source &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;hashicorp&#x2F;aws&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;~&amp;gt; 5.70&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;provider &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;profile &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;default&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Change this to your AWS profile
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;region  &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;us-east-1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Change this to your AWS region
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# MARK: Getting VPC and Subnets
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;locals&lt;&#x2F;span&gt;&lt;span&gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vpc_name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;my_vpc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Change this to yor VPC name
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_vpc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;vpc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  filter {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name   &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;tag:Name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;values &lt;&#x2F;span&gt;&lt;span&gt;= [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.vpc_name]
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_subnets&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  filter {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name   &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;vpc-id&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;values &lt;&#x2F;span&gt;&lt;span&gt;= [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;.aws_vpc.vpc.id]
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tags &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Tier &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Public&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# This is custom tag
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;wireguard-server&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#wireguard-server&quot; aria-label=&quot;Anchor link for: wireguard-server&quot;&gt;WireGuard Server&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;To setup WireGuard server we need to know AMI ID of OS will be running on EC2 instance, prepare key pairs for the server and for client (peers), create a security group to control network access, create and assing Elastic IP to be sure that the server IP will be same.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;generate-key-pairs&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#generate-key-pairs&quot; aria-label=&quot;Anchor link for: generate-key-pairs&quot;&gt;Generate key pairs&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;First we need to create key pairs which can be generated with this command:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;bash -c &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;priv=$(wg genkey); pub=$(echo $priv | wg pubkey); printf &amp;quot;$priv\n$pub\n&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In output first line is privkey, second is pubkey.&lt;&#x2F;p&gt;
&lt;p&gt;I will generate it twice, one for server, second for first client (peer). Then for each new peer you will need to generate new key pairs. I will same generated keys to &lt;code&gt;secrets.yaml&lt;&#x2F;code&gt; file, but you can use different ways to store secrets.&lt;&#x2F;p&gt;
&lt;p&gt;Generate secrets for server and first peer (do not use this keys in your setup):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; bash&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -c &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;priv=$(wg genkey); pub=$(echo $priv | wg pubkey); printf &amp;quot;$priv\n$pub\n&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;0McsAe5Y&#x2F;oupwJeju+94ZFl1bmp2KIX2bBQGk0cSWXQ&lt;&#x2F;span&gt;&lt;span&gt;=
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;KeV+BlZMfCgRhdfaHqpdPp23Nu&#x2F;otir+6VR02DER7lU&lt;&#x2F;span&gt;&lt;span&gt;=
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; bash&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -c &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;priv=$(wg genkey); pub=$(echo $priv | wg pubkey); printf &amp;quot;$priv\n$pub\n&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;SK71fHXpTo2cGKvlLLTlu+0AqpwaNWG30rzGXFIryk0&lt;&#x2F;span&gt;&lt;span&gt;=
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wf3j1JLhXw&#x2F;u6iDZf9Qhq0lU34exF8mrHdGzz&#x2F;u+xFU&lt;&#x2F;span&gt;&lt;span&gt;=
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then save generated keys to &lt;code&gt;secrets.yaml&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wg_server&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;privkey&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0McsAe5Y&#x2F;oupwJeju+94ZFl1bmp2KIX2bBQGk0cSWXQ=
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;pubkey&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;KeV+BlZMfCgRhdfaHqpdPp23Nu&#x2F;otir+6VR02DER7lU=
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wg_peers&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;user1
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;addr&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;172.16.16.1
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;privkey&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;SK71fHXpTo2cGKvlLLTlu+0AqpwaNWG30rzGXFIryk0=
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;pubkey&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;wf3j1JLhXw&#x2F;u6iDZf9Qhq0lU34exF8mrHdGzz&#x2F;u+xFU=
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;setup-script&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#setup-script&quot; aria-label=&quot;Anchor link for: setup-script&quot;&gt;Setup script&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Then we need create WireGuard setup script which will be runned during EC2 creation. User data will be generated from this script and populated from &lt;code&gt;secrets.yaml&lt;&#x2F;code&gt; file. So create &lt;code&gt;templates&lt;&#x2F;code&gt; directory with two files in it: &lt;code&gt;wg-init.tpl&lt;&#x2F;code&gt; (general setup script) and &lt;code&gt;wg-peer.tpl&lt;&#x2F;code&gt; (peer info).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#!&#x2F;bin&#x2F;bash
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; apt update &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;apt -y&lt;&#x2F;span&gt;&lt;span&gt; install net-tools wireguard
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# https:&#x2F;&#x2F;github.com&#x2F;vainkop&#x2F;terraform-aws-wireguard&#x2F;blob&#x2F;master&#x2F;templates&#x2F;user-data.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; mkdir&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;etc&#x2F;wireguard
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; cat &amp;gt; &#x2F;etc&#x2F;wireguard&#x2F;wg0.conf &amp;lt;&amp;lt;- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;EOF
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;[Interface]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;PrivateKey = &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wg_privkey&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ListenPort = &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wg_port&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Address = &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wg_cidr&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;PostUp = sysctl -w -q net.ipv4.ip_forward=1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ENI -j MASQUERADE
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;PostDown = sysctl -w -q net.ipv4.ip_forward=0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ENI -j MASQUERADE
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wg_peers&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;EOF
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Make sure we replace the &amp;quot;ENI&amp;quot; placeholder with the actual network interface name
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ENI&lt;&#x2F;span&gt;&lt;span&gt;=$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ip&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; route get 8.8.8.8 &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;grep&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; 8.8.8.8 &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;awk &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;{print $5}&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; sed&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -i &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;s&#x2F;ENI&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ENI&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;g&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &#x2F;etc&#x2F;wireguard&#x2F;wg0.conf
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; wg-quick up wg0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; systemctl enable wg-quick@wg0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[Peer]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# ${peer_name}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PublicKey&lt;&#x2F;span&gt;&lt;span&gt; = ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;peer_pubkey&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;AllowedIPs&lt;&#x2F;span&gt;&lt;span&gt; = ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;peer_addr&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next we need to prepare user data script in terraform file from this templates.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# MARK: Config
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;locals&lt;&#x2F;span&gt;&lt;span&gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wg_cidr &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;172.16.16.0&#x2F;20&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# CIDR of WireGuard Server
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wg_port &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;51820            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Port of WireGuard Server
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;secrets &lt;&#x2F;span&gt;&lt;span&gt;= yamldecode(file(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;secrets.yaml&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;userdata &lt;&#x2F;span&gt;&lt;span&gt;= templatefile(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;templates&#x2F;wg-init.tpl&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wg_cidr    &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.wg_cidr
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wg_port    &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.wg_port
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wg_privkey &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.secrets.wg_server.privkey
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wg_peers &lt;&#x2F;span&gt;&lt;span&gt;= join(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, [
&lt;&#x2F;span&gt;&lt;span&gt;      for p in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.secrets.wg_peers :
&lt;&#x2F;span&gt;&lt;span&gt;      templatefile(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;templates&#x2F;wg-peer.tpl&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;peer_name   &lt;&#x2F;span&gt;&lt;span&gt;= p.name
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;peer_pubkey &lt;&#x2F;span&gt;&lt;span&gt;= p.pubkey
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;peer_addr   &lt;&#x2F;span&gt;&lt;span&gt;= p.addr
&lt;&#x2F;span&gt;&lt;span&gt;      })
&lt;&#x2F;span&gt;&lt;span&gt;    ])
&lt;&#x2F;span&gt;&lt;span&gt;  })
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;server-setup&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#server-setup&quot; aria-label=&quot;Anchor link for: server-setup&quot;&gt;Server setup&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Then we need to select Ubuntu AMI, create Security Group and Elastic IP.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# MARK: Server dependencies
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_ami&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ubuntu&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;owners      &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;099720109477&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Canonical
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;most_recent &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;  filter {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name   &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;values &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ubuntu&#x2F;images&#x2F;hvm-ssd&#x2F;ubuntu-jammy-22.04-arm64-server-*&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_eip&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;wireguard&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tags &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;wireguard&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_security_group&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;wireguard&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name        &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.vpc_name}-wireguard&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;description &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;SG for WireGuard VPN Server&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vpc_id      &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;.aws_vpc.vpc.id
&lt;&#x2F;span&gt;&lt;span&gt;  ingress {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;from_port   &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.wg_port
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;to_port     &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.wg_port
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;protocol    &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;udp&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cidr_blocks &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.0.0.0&#x2F;0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;description &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Allow WireGuard Traffic&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;  egress {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;from_port   &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;to_port     &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;protocol    &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;-1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cidr_blocks &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.0.0.0&#x2F;0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next we can setup a server and assing Elastic IP to it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_instance&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;wireguard&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;count                       &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ami                         &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;.aws_ami.ubuntu.id
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;instance_type               &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;t4g.nano&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;subnet_id                   &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;.aws_subnets.public.ids[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vpc_security_group_ids      &lt;&#x2F;span&gt;&lt;span&gt;= [aws_security_group.wireguard.id]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;user_data                   &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.userdata
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;user_data_replace_on_change &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tags                        &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;wireguard&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_eip_association&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;wireguard&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;instance_id   &lt;&#x2F;span&gt;&lt;span&gt;= aws_instance.wireguard[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].id
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;allocation_id &lt;&#x2F;span&gt;&lt;span&gt;= aws_eip.wireguard.id
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;client-configuration&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#client-configuration&quot; aria-label=&quot;Anchor link for: client-configuration&quot;&gt;Client configuration&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;To access to WireGuard server we need to have WireGuard &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.wireguard.com&#x2F;install&#x2F;&quot;&gt;client app&lt;&#x2F;a&gt; and valid client config with &lt;code&gt;.conf&lt;&#x2F;code&gt; extension.&lt;&#x2F;p&gt;
&lt;p&gt;We can generated this configs with Terraform Templates as well. So first, lets add new template file called &lt;code&gt;client-conf.tpl&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[Interface]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt; = ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;client_addr&lt;&#x2F;span&gt;&lt;span&gt;}&#x2F;32
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PrivateKey&lt;&#x2F;span&gt;&lt;span&gt; = ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;client_privkey&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;DNS&lt;&#x2F;span&gt;&lt;span&gt; = ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;client_dns&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;[Peer]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Endpoint&lt;&#x2F;span&gt;&lt;span&gt; = ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;server_addr&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PublicKey&lt;&#x2F;span&gt;&lt;span&gt; = ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;server_pubkey&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;AllowedIPs&lt;&#x2F;span&gt;&lt;span&gt; = ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;client_routes&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PersistentKeepalive&lt;&#x2F;span&gt;&lt;span&gt; = 25
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And add this code to generate client config to out terraform file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# MARK: Export client configuration
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;locals&lt;&#x2F;span&gt;&lt;span&gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;vpc&#x2F;latest&#x2F;userguide&#x2F;AmazonDNS-concepts.html#AmazonDNS
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;client_dns &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;169.254.169.253&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.1.1.1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.0.0.1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;client_routes &lt;&#x2F;span&gt;&lt;span&gt;= [
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;.aws_vpc.vpc.cidr_block, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# All IPs in the VPC
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;169.254.169.253&#x2F;32&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# AWS DNS
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# &amp;quot;0.0.0.0&#x2F;32&amp;quot;,                # Route all traffic through VPN (uncomment if you want this)
&lt;&#x2F;span&gt;&lt;span&gt;  ]
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;local_file&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;peer_conf&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;for_each &lt;&#x2F;span&gt;&lt;span&gt;= { for index, p in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.secrets.wg_peers : p.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;=&amp;gt; p }
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;filename &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;generated&#x2F;${each.value.name}.conf&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;content &lt;&#x2F;span&gt;&lt;span&gt;= templatefile(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;templates&#x2F;client-conf.tpl&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;server_addr    &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${aws_eip.wireguard.public_ip}:${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.wg_port}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;server_pubkey  &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.secrets.wg_server.pubkey,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;client_addr    &lt;&#x2F;span&gt;&lt;span&gt;= each.value.addr,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;client_privkey &lt;&#x2F;span&gt;&lt;span&gt;= each.value.privkey,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;client_dns     &lt;&#x2F;span&gt;&lt;span&gt;= join(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.client_dns),
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;client_routes  &lt;&#x2F;span&gt;&lt;span&gt;= join(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.client_routes),
&lt;&#x2F;span&gt;&lt;span&gt;  })
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;execute&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#execute&quot; aria-label=&quot;Anchor link for: execute&quot;&gt;Execute&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Finally we can run &lt;code&gt;terraform init&lt;&#x2F;code&gt; &amp;amp; &lt;code&gt;terraform apply&lt;&#x2F;code&gt;. In less then a minute VPN server will be created and user client will be exported to &lt;code&gt;generated&#x2F;user1.conf&lt;&#x2F;code&gt;. Then we can share this file with our teammates.&lt;&#x2F;p&gt;
&lt;p&gt;To check VPN connection working fine you can export &lt;code&gt;.conf&lt;&#x2F;code&gt; into WireGuard client. Then for example I check my RDS instance before VPN enabled and after.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; dig +short my-rds.4oexsiqydp8q.us-east-1.rds.amazonaws.com
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ec2-34-226-xx-xx.compute-1.amazonaws.com.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;34.226.xx.xx
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; dig +short my-rds.4oexsiqydp8q.us-east-1.rds.amazonaws.com
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ec2-34-226-xx-xx.compute-1.amazonaws.com.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;10.10.20.80
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;adding-clients&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#adding-clients&quot; aria-label=&quot;Anchor link for: adding-clients&quot;&gt;Adding clients&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Adding new client configuration is quite simple. We need to generate new key pair:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span&gt; bash&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -c &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;priv=$(wg genkey); pub=$(echo $priv | wg pubkey); printf &amp;quot;$priv\n$pub\n&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ALqgaUiWd0rtcLza2K143x5RwS0Y5zwh3YwHx&#x2F;L7nV0&lt;&#x2F;span&gt;&lt;span&gt;=
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;u1yQmh&#x2F;G7n+S8aCp0PRuRuAuacmqYNzHLCPOcl9aS28&lt;&#x2F;span&gt;&lt;span&gt;=
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then update &lt;code&gt;secrets.yaml&lt;&#x2F;code&gt; file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;wg_peers&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# ...
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;user2
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;addr&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;172.16.16.2
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;privkey&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ALqgaUiWd0rtcLza2K143x5RwS0Y5zwh3YwHx&#x2F;L7nV0=
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;pubkey&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;u1yQmh&#x2F;G7n+S8aCp0PRuRuAuacmqYNzHLCPOcl9aS28=
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And run &lt;code&gt;terraform apply&lt;&#x2F;code&gt; again. Server will be re-created (!) with new configuration. Note that existing clients will be disconnected during deploy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#summary&quot; aria-label=&quot;Anchor link for: summary&quot;&gt;Summary&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;WireGuard provides easy solution for creating VPN server. We created cheap and fast setup to access to internal AWS VPC with ability to create different clients configurations, which can be shared with out team members.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;PS. Source files of this article can be found &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;blog&#x2F;tree&#x2F;main&#x2F;code&#x2F;aws-wireguard-terraform&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Fast multi-arch Docker build for Rust projects</title>
        <published>2024-10-04T00:00:00+00:00</published>
        <updated>2024-10-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/fast-multi-arch-docker-for-rust/"/>
        <id>https://vladkens.cc/fast-multi-arch-docker-for-rust/</id>
        
        <content type="html" xml:base="https://vladkens.cc/fast-multi-arch-docker-for-rust/">&lt;p&gt;&lt;img src=&quot;&#x2F;rust-docker-build-cover.png&quot; alt=&quot;post cover image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Rust allows programs to run very fast and memory efficient, but it has a cost – compile time. In web development, it is standard practice to deliver programs as Docker images and then run them in Kubernetes &#x2F; &lt;a href=&quot;&#x2F;aws-ecs-cluster&#x2F;&quot;&gt;Amazon ECS&lt;&#x2F;a&gt; &#x2F; Docker Compose &#x2F; etc. After the popularity of ARM processors in recent years, programmers have been faced with the additional step of preparing multi-arch Docker images (meaning that the same image should be able to run natively on both x86-64&#x2F;amd64 and aarch64&#x2F;arm64 processors).&lt;&#x2F;p&gt;
&lt;p&gt;Preparing Docker images for interpreted languages is usually not a problem – Docker Buildx is used, which in turn runs inside the emulator and builds the image for each architucture natively. NodeJS &#x2F; Python just install dependencies via npm &#x2F; pip, copy the project code, does a little polishing and that&#x27;s pretty much it. Even in compiled Go this approach works fine because Go has an extensive standard library. In the case of Rust, compiling even a simple web application is a rebuilding of the “universe” – almost any web application requires: HTTP-server, HTTP-client (which in turn requires a library to work with cryptography for https), asynchronous runtime (tokie, etc), serialization&#x2F;desirialization (serde, serde_json); which in Rust should be installed as external libraries (crates) and should be compiled each time when program builded.&lt;&#x2F;p&gt;
&lt;p&gt;Although Rust compiler has a lot of work to do, it can do it quickly. Even not strongest CI, will build an average project in a couple of minutes. However, this is true only in case of building on native architecture (for example building amd64 binary on an amd64 processor). As soon as we need to build a multi-arch image, we have to do emulation and the compilation speed drops dramatically. For example, on my simple public project – &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;ghstats&quot;&gt;ghstats&lt;&#x2F;a&gt;, building multi-arch image from scratch took about 50 minutes, when same build for native architecture takes 2-3 minutes.&lt;&#x2F;p&gt;
&lt;p&gt;Building time can be optimized by proper usage of Docker layers, so that the step with rebuilding dependencies occurs only when they are actually changed. So only the first build will be long and following builds will be fast. Unfortunately, Rust infrastructure have a problem in this point –
any change in &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt; file (for example version number) will invalidate Docker layer and triggers full rebuild of all dependencies.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;problem-definition&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#problem-definition&quot; aria-label=&quot;Anchor link for: problem-definition&quot;&gt;Problem definition&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;So there are two problems with building multi-arch Docker images for Rust projects:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Layer invalidation and full rebuild on any change in &lt;code&gt;Cargo.toml &lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Very slow multi-arch build due to emulation&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;better-dependencies-building&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#better-dependencies-building&quot; aria-label=&quot;Anchor link for: better-dependencies-building&quot;&gt;Better dependencies building&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Easiest way to solve the first problem is to use &lt;code&gt;cargo-chef&lt;&#x2F;code&gt; which was created exacly for it. &lt;code&gt;cargo-chef&lt;&#x2F;code&gt; converts &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt; &amp;amp; &lt;code&gt;Cargo.lock&lt;&#x2F;code&gt; into a special &lt;code&gt;recipe.json&lt;&#x2F;code&gt; file that will remain unchanged until project dependencies are unchanged. Then we can use this json file to cache expensive Docker layer that compiles dependencies.&lt;&#x2F;p&gt;
&lt;p&gt;Dockerfile with &lt;code&gt;cargo-chef&lt;&#x2F;code&gt; will use multi-stage build splited to 5 parts:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Installing &lt;code&gt;cargo-chef&lt;&#x2F;code&gt; and build dependencies (OpenSSL, linux-headers, etc)&lt;&#x2F;li&gt;
&lt;li&gt;Preparing &lt;code&gt;recipe.json&lt;&#x2F;code&gt; file with project dependencies description&lt;&#x2F;li&gt;
&lt;li&gt;Installing &amp;amp; builiding project dependencies from &lt;code&gt;recipe.json&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Building whole project&lt;&#x2F;li&gt;
&lt;li&gt;Copy binaries to runtime image and final polishing&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Example of Dockerfile with &lt;code&gt;cargo-chef&lt;&#x2F;code&gt; and multi-stage build (I use alpine in my projects, but you can use other base-images).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dockerfile&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-dockerfile &quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# (1) installing cargo-chef &amp;amp; build deps
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; rust:alpine &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;AS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;chef
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;cargo install --locked cargo-chef
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;apk add --no-cache musl-dev openssl-dev
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# (2) prepating recipe file
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; chef &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;AS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;planner
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; . .
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;cargo chef prepare --recipe-path recipe.json
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# (3) building project deps, cache magic happen on COPY command
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; chef &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;AS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;builder
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; --from=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;planner&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;app&#x2F;recipe.json recipe.json
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;cargo chef cook --recipe-path recipe.json --release
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# (4) actual project build
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; . .
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;cargo build -r
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# (5) runtime image, you can use any base image you want
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; alpine:latest &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;AS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;runtime
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; --from=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;builder&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;app&#x2F;target&#x2F;release&#x2F;prog &#x2F;app&#x2F;prog
&lt;&#x2F;span&gt;&lt;span&gt;CMD &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;app&#x2F;prog&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This approach will speed up Docker image build many times while project dependencies are not changed. Because Docker builds stages separately, &lt;em&gt;planner&lt;&#x2F;em&gt; stage will be executed each time (but &lt;code&gt;cargo-chef&lt;&#x2F;code&gt; is fast!) and &lt;em&gt;builder&lt;&#x2F;em&gt; stage will be partially cached until &lt;code&gt;recipe.json&lt;&#x2F;code&gt; file are same.&lt;&#x2F;p&gt;
&lt;p&gt;If you need single architecture build this will work fine. But if you need multi-arch images, this approach still be slow.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;multi-arch-image-with-cross-compilation&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#multi-arch-image-with-cross-compilation&quot; aria-label=&quot;Anchor link for: multi-arch-image-with-cross-compilation&quot;&gt;Multi-arch image with cross-compilation&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Multi-arch builds using Docker Buildx run very slow due to QEMU emulation. If we get rid of emulation, compilation will be at full speed. Rust has built-in cross-compilation for other architectures, so we adapt it in Docker build.&lt;&#x2F;p&gt;
&lt;p&gt;Cross-compilation in Rust itself works fine, but some crates are based on C libraries (OpenSSL, SQLite, etc). Compiling and linking C code is quite complicated and not always clear (usually you have to look for error codes somewhere on Stack Overflow or Github Issues until you get the right set of compilers&#x2F;header files added). There is another tool that surprisingly solves the problem of cross-compiling C code very well – Zig (actually this is programming language, but they have build toolchain as well).&lt;&#x2F;p&gt;
&lt;p&gt;To connect Zig build toolchain with Rust I will use &lt;code&gt;cargo-zigbuild&lt;&#x2F;code&gt; crate. I other Docker file looks pretty same to our &lt;code&gt;cargo-chef&lt;&#x2F;code&gt; variant, expect I added second target in Cargo to build and &lt;code&gt;cargo build&lt;&#x2F;code&gt; replaced with &lt;code&gt;cargo zigbuild&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;dockerfile&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-dockerfile &quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# (1) this stage will be run always on current arch
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# zigbuild &amp;amp; Cargo targets added
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; --platform=$BUILDPLATFORM rust:alpine AS chef
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ENV &lt;&#x2F;span&gt;&lt;span&gt;PKG_CONFIG_SYSROOT_DIR=&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;apk add --no-cache musl-dev openssl-dev zig
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;cargo install --locked cargo-zigbuild cargo-chef
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;rustup target add x86_64-unknown-linux-musl aarch64-unknown-linux-musl
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# (2) nothing changed
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; chef &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;AS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;planner
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; . .
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;cargo chef prepare --recipe-path recipe.json
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# (3) building project deps: need to specify all targets; zigbuild used
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; chef &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;AS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;builder
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; --from=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;planner&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;app&#x2F;recipe.json recipe.json
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;cargo chef cook --recipe-path recipe.json --release --zigbuild \
&lt;&#x2F;span&gt;&lt;span&gt;    --target x86_64-unknown-linux-musl --target aarch64-unknown-linux-musl
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# (4) actuall project build for all targets
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# binary renamed to easier copy in runtime stage
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; . .
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;cargo zigbuild -r \
&lt;&#x2F;span&gt;&lt;span&gt;    --target x86_64-unknown-linux-musl --target aarch64-unknown-linux-musl &amp;amp;&amp;amp; \
&lt;&#x2F;span&gt;&lt;span&gt;    mkdir &#x2F;app&#x2F;linux &amp;amp;&amp;amp; \
&lt;&#x2F;span&gt;&lt;span&gt;    cp target&#x2F;aarch64-unknown-linux-musl&#x2F;release&#x2F;prog &#x2F;app&#x2F;linux&#x2F;arm64 &amp;amp;&amp;amp; \
&lt;&#x2F;span&gt;&lt;span&gt;    cp target&#x2F;x86_64-unknown-linux-musl&#x2F;release&#x2F;prog &#x2F;app&#x2F;linux&#x2F;amd64
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# (5) this staged will be emulated as was before
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# TARGETPLATFORM usage to copy right binary from builder stage
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# ARG populated by docker itself
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; alpine:latest &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;AS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;runtime
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ARG &lt;&#x2F;span&gt;&lt;span&gt;TARGETPLATFORM
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; --from=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;builder&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;app&#x2F;${TARGETPLATFORM} &#x2F;app&#x2F;prog
&lt;&#x2F;span&gt;&lt;span&gt;CMD &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;app&#x2F;prog&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In general that all. Such build approach will work faster. For my project:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;initial build 50 min → 13 min (3.8x)&lt;&#x2F;li&gt;
&lt;li&gt;code updated 7 min → 3 min (2.3x)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Additional performance can be achieved by moving first step into separate base image, then our main Docker image will not need to build &lt;code&gt;cargo-zibguild&lt;&#x2F;code&gt; and &lt;code&gt;cargo-chef&lt;&#x2F;code&gt; (-2 min from initial build).&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: If you already know your server architecture (if you build your docker for a specific server), you can remove everything link to the other architecture. This will lead you to have performance improvement in both initial build and updates.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.docker.com&#x2F;blog&#x2F;faster-multi-platform-builds-dockerfile-cross-compilation-guide&quot;&gt;https:&#x2F;&#x2F;www.docker.com&#x2F;blog&#x2F;faster-multi-platform-builds-dockerfile-cross-compilation-guide&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>apigen-ts – Simple TypeScript API Client Generator</title>
        <published>2024-09-04T00:00:00+00:00</published>
        <updated>2024-09-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/simple-typescript-api-client-generator/"/>
        <id>https://vladkens.cc/simple-typescript-api-client-generator/</id>
        
        <content type="html" xml:base="https://vladkens.cc/simple-typescript-api-client-generator/">&lt;img src=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;vladkens&#x2F;apigen-ts&#x2F;HEAD&#x2F;logo.svg&quot; alg=&quot;logo&quot; style=&quot;padding-top: 15px&quot; &#x2F;&gt;
&lt;p&gt;OpenAPI &#x2F; Swagger is a good way to describe API contracts between backend &#x2F; frontend or different services. Nowadays frontend is almost always TypeScript + some framework (React, Vue, Angular, etc). Backend in turn can be in NodeJS (and then in principle you can share contracts with code reuse), or in another language (e.g. Python &#x2F; Go &#x2F; Scala &#x2F; Rust) and then code reuse and API synchronization becomes a problem.&lt;&#x2F;p&gt;
&lt;p&gt;OpenAPI can solve this problem through codegen – backend should qualitatively describe the available API methods and data types, after that you can use the client generation utility and get ready typed TypeScript code.&lt;&#x2F;p&gt;
&lt;p&gt;OpenAPI has a standard tool for such generation, but it has a number of problems:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Tool is written in Java, which requires special software to be installed on dev computer &#x2F; CI&lt;&#x2F;li&gt;
&lt;li&gt;Generate client is extensive and consists of many &lt;code&gt;.ts&lt;&#x2F;code&gt; files, which makes it not user friendly (in my opinion)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In JavaScript ecosystem it is common to use npm (or yarn &#x2F; pnpm – whatever you like more) as a package manager. But the point is the same: packages are written in JavaScript, installed from one place, versioned.&lt;&#x2F;p&gt;
&lt;p&gt;In npm you can find several alternative apigen utilities written in TypeScript which provides a better development experience. I used one of those too (swagger-typescript-api), until they changed interfaces a few times and I had to fix my several projects. I tried to find an alternative in npm, but all available generators (as of late 2023) also have their own problems: generate a lot of files, are difficult to configure, break compatibility between versions, require to install additional packages.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;meet-apigen-ts&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#meet-apigen-ts&quot; aria-label=&quot;Anchor link for: meet-apigen-ts&quot;&gt;Meet apigen-ts&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I have a couple of projects in NestJS &#x2F; FastAPI in support mode, for which I just need a stable API client generation utility that is simple and won&#x27;t change often. So I wrote my own TypeScript HTTP API generation package from Swagger specification – &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;apigen-ts&quot;&gt;apigen-ts&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Originally I wrote &lt;code&gt;apigen-ts&lt;&#x2F;code&gt; for personal projects, but then I share it to my friends and they also started to use &lt;code&gt;apigen-ts&lt;&#x2F;code&gt; in their projects. Now I want to share it with the community, maybe it will be useful for someone too. So library features:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;supports Swagger &#x2F; OpenAPI v2 &#x2F; v3 &#x2F; v3.1 (parsed with &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Redocly&quot;&gt;redocly&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;generates a typed TypeScript client&lt;&#x2F;li&gt;
&lt;li&gt;single output file, single api class&lt;&#x2F;li&gt;
&lt;li&gt;exports data models for use in your code&lt;&#x2F;li&gt;
&lt;li&gt;automatic code formatting with prettier (peer dependency)&lt;&#x2F;li&gt;
&lt;li&gt;ability to &lt;a href=&quot;&#x2F;rest-api-date-parsing&#x2F;&quot;&gt;automatic dates parsing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;usage&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#usage&quot; aria-label=&quot;Anchor link for: usage&quot;&gt;Usage&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Usage is as simple as possible and is divided into two steps: generating a client from specification (local file or remote url; yaml or json), using the generated typed client in the app.&lt;&#x2F;p&gt;
&lt;p&gt;Generation of an arbitrary client can be performed by command:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;npx -y&lt;&#x2F;span&gt;&lt;span&gt; apigen-ts https:&#x2F;&#x2F;petstore3.swagger.io&#x2F;api&#x2F;v3&#x2F;openapi.json .&#x2F;api-client.ts
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or you can install &lt;code&gt;apigen-ts&lt;&#x2F;code&gt; as a dev dependency (&lt;code&gt;npm i -D apigen-ts&lt;&#x2F;code&gt;) and create a task to generate the client in &lt;code&gt;package.json&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;my-frontend&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;scripts&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: {
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;apigen&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;apigen-ts http:&#x2F;&#x2F;127.0.0.1:3000&#x2F;docs-json .&#x2F;api-client.ts --parse-dates &amp;amp;&amp;amp; tsc --noEmit&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then use: &lt;code&gt;npm run apigen&lt;&#x2F;code&gt; or &lt;code&gt;yarn apigen&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Generated file contains a client class named &lt;code&gt;ApiClient&lt;&#x2F;code&gt; and TypeScript types used in API endpoints. Next you can use them in app code in the following way:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-ts &quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ApiClient&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Pet &lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.&#x2F;api-client&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;api &lt;&#x2F;span&gt;&lt;span&gt;= new ApiClient({
&lt;&#x2F;span&gt;&lt;span&gt;  baseUrl: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;example.com&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;  headers: { Authorization: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;secret-token&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; },
&lt;&#x2F;span&gt;&lt;span&gt;});
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; GET https:&#x2F;&#x2F;example.com&#x2F;pet&#x2F;findByStatus?status=sold
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;pet&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;findPetsByStatus&lt;&#x2F;span&gt;&lt;span&gt;({ status: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sold&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; -&amp;gt; Pet[]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Generator tries to create method names in format like &lt;code&gt;{domain}.{operation}&lt;&#x2F;code&gt;. The types used in Swagger spec can be imported directly into code (in example above &lt;code&gt;Pet&lt;&#x2F;code&gt; is generated type). This approach makes it easy to track changes in contract and fix the application code where types are updated or methods are changed (of course if you describe your Swagger well). Just run new api generation and check frontend code for errors afterwards with TypeScript.&lt;&#x2F;p&gt;
&lt;p&gt;Also &lt;code&gt;apigen-ts&lt;&#x2F;code&gt; works well in CI pipelines, when on new commits to the backend part you run frontend api client generation and check code compatibility.&lt;&#x2F;p&gt;
&lt;p&gt;The generated client uses native fetch API (does not require additional packages) and can be used both in browser and NodeJS environment. If you use &lt;code&gt;prettier&lt;&#x2F;code&gt; in your project, the generated client will be automatically formatted according to project settings.&lt;&#x2F;p&gt;
&lt;p&gt;More configuration options and customization abilities can be in &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;apigen-ts&quot;&gt;readme&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot;&gt;Conclusion&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Backend ↔ frontend (or backend ↔ backend) communication is monotonous and repetitive work from project to project. Do not waste time and effort on manual writing of api clients. Instead use simple tools to automate process and keep code quality.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;You can support this project with a star ⭐️ or leave an issue &#x2F; feature request on &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;apigen-ts&quot;&gt;Github page&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Table sorting and pagination with HTMX</title>
        <published>2024-08-18T00:00:00+00:00</published>
        <updated>2024-08-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/htmx-table-sorting/"/>
        <id>https://vladkens.cc/htmx-table-sorting/</id>
        
        <content type="html" xml:base="https://vladkens.cc/htmx-table-sorting/">&lt;p&gt;I recently tried HTMX for my new project – &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;ghstats&quot;&gt;ghstats&lt;&#x2F;a&gt; – a dashboard of Github repository traffic in a single interface for longer than 14 days. This project was planned as a self-hosted service, so I was thinking about a really simple and memory-less tech stack. Last time I played with Rust, so I decided to use it instead of NodeJS &#x2F; Python. Of course, if I&#x27;m generating static HTML on the server side, I have two options for implementing table sorting and pagination: use query parameters and do everything on backend, or use some JavaScript to call data from the backend and render the table on the client side. But HTMX offers a new, third way: write all the logic on the backend and replace the necessary parts of HTML with just a few tag attributes. Let&#x27;s see how it works.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;initial-setup&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#initial-setup&quot; aria-label=&quot;Anchor link for: initial-setup&quot;&gt;Initial setup&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;To demonstrate table sorting and pagination, I&#x27;ll be using the same stack I used for my service: &lt;code&gt;axum&lt;&#x2F;code&gt; as a backend framework and &lt;code&gt;maud&lt;&#x2F;code&gt; for HTML templating (it&#x27;s a DSL over Rust templates).&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s create new project with:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cargo&lt;&#x2F;span&gt;&lt;span&gt; init htmx-example &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cd-html-example
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then install dependencies:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cargo&lt;&#x2F;span&gt;&lt;span&gt; add tokio axum maud&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --features&lt;&#x2F;span&gt;&lt;span&gt; tokio&#x2F;full,maud&#x2F;axum
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and do initial setup in &lt;code&gt;src&#x2F;main.rs&lt;&#x2F;code&gt; file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;axum::{response::IntoResponse, routing::get, Router};
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;maud::html;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;index_page&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; impl IntoResponse {
&lt;&#x2F;span&gt;&lt;span&gt;  html! {
&lt;&#x2F;span&gt;&lt;span&gt;    h1 { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Hello, World!&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tokio&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; service = Router::new().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;route&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(index_page)).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_make_service&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; listener = tokio::net::TcpListener::bind(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;127.0.0.1:8080&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).await.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;  axum::serve(listener, service).await.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then we cant run this with &lt;code&gt;cargo watch -x run&lt;&#x2F;code&gt; and open &lt;code&gt;http:&#x2F;&#x2F;127.0.0.1:8080&lt;&#x2F;code&gt; in the browser. &quot;Hello, World!&quot; should be displayed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;creating-a-static-table&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#creating-a-static-table&quot; aria-label=&quot;Anchor link for: creating-a-static-table&quot;&gt;Creating a static table&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s add crates to generate random data:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cargo&lt;&#x2F;span&gt;&lt;span&gt; add fake rand rand_chacha&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --features&lt;&#x2F;span&gt;&lt;span&gt; fake&#x2F;derive
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and define simple &lt;code&gt;Contact&lt;&#x2F;code&gt; struct (like our application is simple CMS).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;fake::faker::company::en::*;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;fake::faker::internet::en::*;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;fake::faker::name::en::*;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;fake::faker::phone_number::en::*;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;fake::{Dummy, Fake, Faker};
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;rand::prelude::*;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;rand_chacha::ChaCha8Rng;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Debug, Clone, Dummy)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Contact {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dummy&lt;&#x2F;span&gt;&lt;span&gt;(faker = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Name()&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: String,
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dummy&lt;&#x2F;span&gt;&lt;span&gt;(faker = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CompanyName()&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;company&lt;&#x2F;span&gt;&lt;span&gt;: String,
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dummy&lt;&#x2F;span&gt;&lt;span&gt;(faker = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;FreeEmail()&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;email&lt;&#x2F;span&gt;&lt;span&gt;: String,
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  #[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dummy&lt;&#x2F;span&gt;&lt;span&gt;(faker = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;PhoneNumber()&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;phone&lt;&#x2F;span&gt;&lt;span&gt;: String,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get_contacts&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;n&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Vec&amp;lt;Contact&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; items = Vec::with_capacity(n);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; rng = ChaCha8Rng::seed_from_u64(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;42&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;_ in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;..n {
&lt;&#x2F;span&gt;&lt;span&gt;    items.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(Faker.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;fake_with_rng&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; rng));
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;  items
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;index_page&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; impl IntoResponse {
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; contacts = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_contacts&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;	println!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{:?}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, contacts[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;span&gt;	println!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{:?}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, contacts[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  html! {
&lt;&#x2F;span&gt;&lt;span&gt;    h1 { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Hello, World!&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now on each request same random contacts will be generated, so we can use this data in our table.
&lt;code&gt;get_contacts&lt;&#x2F;code&gt; function emulates database query in real environment.&lt;&#x2F;p&gt;
&lt;p&gt;I will also add base layout for page with &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;picocss.com&#x2F;&quot;&gt;PicoCSS&lt;&#x2F;a&gt; framework to have nice look:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;base&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;html&lt;&#x2F;span&gt;&lt;span&gt;: maud::Markup) -&amp;gt; impl IntoResponse {
&lt;&#x2F;span&gt;&lt;span&gt;  html! {
&lt;&#x2F;span&gt;&lt;span&gt;    html {
&lt;&#x2F;span&gt;&lt;span&gt;      head {
&lt;&#x2F;span&gt;&lt;span&gt;        meta charset=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;utf-8&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {}
&lt;&#x2F;span&gt;&lt;span&gt;        title { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Contacts&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        link rel=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;stylesheet&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; href=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;unpkg.com&#x2F;@picocss&#x2F;pico@2.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {}
&lt;&#x2F;span&gt;&lt;span&gt;        script src=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;unpkg.com&#x2F;htmx.org@2.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {}
&lt;&#x2F;span&gt;&lt;span&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;      body class=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;container&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;        { (html) }
&lt;&#x2F;span&gt;&lt;span&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And finally update &lt;code&gt;index_page&lt;&#x2F;code&gt; to render contact table:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;index_page&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; impl IntoResponse {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; contacts = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_contacts&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;base&lt;&#x2F;span&gt;&lt;span&gt;(html! {
&lt;&#x2F;span&gt;&lt;span&gt;    table {
&lt;&#x2F;span&gt;&lt;span&gt;      thead {
&lt;&#x2F;span&gt;&lt;span&gt;        tr {
&lt;&#x2F;span&gt;&lt;span&gt;          th { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ID&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;          th { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;          th { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Company&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;          th { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Email&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;          th { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Phone&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;      tbody {
&lt;&#x2F;span&gt;&lt;span&gt;        @&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; contact in contacts {
&lt;&#x2F;span&gt;&lt;span&gt;          tr {
&lt;&#x2F;span&gt;&lt;span&gt;            td { (contact.id) }
&lt;&#x2F;span&gt;&lt;span&gt;            td { (contact.name) }
&lt;&#x2F;span&gt;&lt;span&gt;            td { (contact.company) }
&lt;&#x2F;span&gt;&lt;span&gt;            td { (contact.email) }
&lt;&#x2F;span&gt;&lt;span&gt;            td { (contact.phone) }
&lt;&#x2F;span&gt;&lt;span&gt;          }
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  })
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can request again &lt;code&gt;http:&#x2F;&#x2F;127.0.0.1:8080&lt;&#x2F;code&gt; and see our table with random contacts (which on each request at same).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sorting-table&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#sorting-table&quot; aria-label=&quot;Anchor link for: sorting-table&quot;&gt;Sorting table&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Now is the time to add sorting to our table. We will use HTMX to send requests to the server and get sorted HTML back. First, we need to add sorting logic to our backend. We will use query parameters to pass sorting column and direction.&lt;&#x2F;p&gt;
&lt;p&gt;To make it easier, I will add struct &lt;code&gt;TableFilter&lt;&#x2F;code&gt; which will represent sorting and pagination parameters, for code simplicity I will parse Request manually rather than using &lt;code&gt;Query&lt;&#x2F;code&gt; extractor and &lt;code&gt;serde&lt;&#x2F;code&gt; crate:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::collections::HashMap;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;axum::extract::{Query, Request};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Debug)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;TableFilter {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sort&lt;&#x2F;span&gt;&lt;span&gt;: String,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;order&lt;&#x2F;span&gt;&lt;span&gt;: String,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;page&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;per_page&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;parse_table_filter&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;req&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;Request) -&amp;gt; TableFilter {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; qs: Query&amp;lt;HashMap&amp;lt;String, String&amp;gt;&amp;gt; = Query::try_from_uri(req.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;uri&lt;&#x2F;span&gt;&lt;span&gt;()).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; sort = qs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sort&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;()).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; order = qs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;order&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;desc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;()).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; page = qs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;page&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;()).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;parse&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; per_page = qs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;per_page&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;()).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;parse&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;  TableFilter { sort, order, page, per_page }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, we need to create a function to render &lt;code&gt;th&lt;&#x2F;code&gt; with HTMX attributes to handle sorting:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;title&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;qs&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;TableFilter) -&amp;gt; maud::Markup {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; id = title.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_lowercase&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; order = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; qs.sort == id &amp;amp;&amp;amp; qs.order == &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;desc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;asc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{ &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;desc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; };
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; url = format!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;?sort=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;amp;order=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;amp;page=1&amp;amp;per_page=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, id, order, qs.per_page);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  html! {
&lt;&#x2F;span&gt;&lt;span&gt;    th scope=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;col&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; style=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;cursor: pointer;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      hx-trigger=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;click&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      hx-get=(url)
&lt;&#x2F;span&gt;&lt;span&gt;      hx-target=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;#contacts_table&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      hx-swap=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;outerHTML&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;      (title)
&lt;&#x2F;span&gt;&lt;span&gt;      @&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; qs.sort == id {
&lt;&#x2F;span&gt;&lt;span&gt;        span style=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;margin-left: 0.5em;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;          @&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; qs.order == &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;asc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;↑&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; } @&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{ &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;↓&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Update &lt;code&gt;get_contacts&lt;&#x2F;code&gt; to accept &lt;code&gt;TableFilter&lt;&#x2F;code&gt; and sort items &#x2F; do pagination:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get_contacts&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;n&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;qs&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;TableFilter) -&amp;gt; (Vec&amp;lt;Contact&amp;gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; items: Vec&amp;lt;Contact&amp;gt; = Vec::with_capacity(n);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; rng = ChaCha8Rng::seed_from_u64(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;42&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;_ in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;..n {
&lt;&#x2F;span&gt;&lt;span&gt;    items.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(Faker.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;fake_with_rng&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; rng));
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  items.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;sort_by&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;| {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; cmp = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; qs.sort.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;as_str&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; =&amp;gt; a.id.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cmp&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;b.id),
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; =&amp;gt; a.name.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cmp&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;b.name),
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;company&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; =&amp;gt; a.company.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cmp&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;b.company),
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;email&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; =&amp;gt; a.email.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cmp&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;b.email),
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;phone&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; =&amp;gt; a.phone.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cmp&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;b.phone),
&lt;&#x2F;span&gt;&lt;span&gt;      _ =&amp;gt; a.id.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cmp&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;b.id),
&lt;&#x2F;span&gt;&lt;span&gt;    };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; qs.order == &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;asc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;      cmp
&lt;&#x2F;span&gt;&lt;span&gt;    } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      cmp.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;reverse&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  });
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; pages = (items.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;() as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64 &lt;&#x2F;span&gt;&lt;span&gt;&#x2F; qs.per_page as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;ceil&lt;&#x2F;span&gt;&lt;span&gt;() as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; range_s = (qs.page as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize &lt;&#x2F;span&gt;&lt;span&gt;- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;) * qs.per_page as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; range_e = qs.page as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize &lt;&#x2F;span&gt;&lt;span&gt;* qs.per_page as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; items = items[range_s..range_e].&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_vec&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  (items, pages)
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And finally, we can update our &lt;code&gt;index_page&lt;&#x2F;code&gt; to use &lt;code&gt;TableFilter&lt;&#x2F;code&gt; and &lt;code&gt;th&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;index_page&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;req&lt;&#x2F;span&gt;&lt;span&gt;: Request) -&amp;gt; impl IntoResponse {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; qs = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;parse_table_filter&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;req);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;(contacts, pages) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_contacts&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;, &amp;amp;qs);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;base&lt;&#x2F;span&gt;&lt;span&gt;(html! {
&lt;&#x2F;span&gt;&lt;span&gt;  	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; id added to tell HTMX where to put new data
&lt;&#x2F;span&gt;&lt;span&gt;    table id=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;contacts_table&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;      thead {
&lt;&#x2F;span&gt;&lt;span&gt;        tr {
&lt;&#x2F;span&gt;&lt;span&gt;          (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ID&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;qs))
&lt;&#x2F;span&gt;&lt;span&gt;          (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;qs))
&lt;&#x2F;span&gt;&lt;span&gt;          (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Company&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;qs))
&lt;&#x2F;span&gt;&lt;span&gt;          (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Email&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;qs))
&lt;&#x2F;span&gt;&lt;span&gt;          (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Phone&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;qs))
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; same as before
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  })
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s it! Now we can sort our table by clicking on the column header. HTMX will send a request to the server with sorting parameters and replace the table with the new sorted data. Let&#x27;s me explain HTMX attributes:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;hx-trigger&lt;&#x2F;code&gt; - event which will trigger the request, in our case it&#x27;s &lt;code&gt;click&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;hx-get&lt;&#x2F;code&gt; - URL to send the request and HTTP method (can be GET or POST)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;hx-target&lt;&#x2F;code&gt; - CSS selector to replace with new data&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;hx-swap&lt;&#x2F;code&gt; - how to replace the target, in our case it&#x27;s &lt;code&gt;outerHTML&lt;&#x2F;code&gt; which will replace the whole table (by default it&#x27;s inserting new data into the target)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;All this attributes handled automatically by HTMX, so we just need to include HTMX script in &lt;code&gt;&amp;lt;head&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pagination&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#pagination&quot; aria-label=&quot;Anchor link for: pagination&quot;&gt;Pagination&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In previous step we already parse pagination filters to struct, so lets add code to render pagination links. I will use code from my another &lt;code&gt;react&lt;&#x2F;code&gt; project, which originally from StackOverflow answer:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;70263913
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;calc_pagination&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;page&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;total&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; Vec&amp;lt;Option&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::cmp::{max, min};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; len = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; len == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5 &lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{ len };
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; total = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;max&lt;&#x2F;span&gt;&lt;span&gt;(total, page);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; start =
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;max&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;min&lt;&#x2F;span&gt;&lt;span&gt;(page as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;isize &lt;&#x2F;span&gt;&lt;span&gt;- ((len - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;) as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;isize &lt;&#x2F;span&gt;&lt;span&gt;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;), total as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;isize &lt;&#x2F;span&gt;&lt;span&gt;- len as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;isize &lt;&#x2F;span&gt;&lt;span&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;      as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; end = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;min&lt;&#x2F;span&gt;&lt;span&gt;(total, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;max&lt;&#x2F;span&gt;&lt;span&gt;(page + (len - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;) &#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;, len - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;));
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; result = Vec::new();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; start &amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    result.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(Some(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;));
&lt;&#x2F;span&gt;&lt;span&gt;    result.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(None);
&lt;&#x2F;span&gt;&lt;span&gt;  } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else if&lt;&#x2F;span&gt;&lt;span&gt; start &amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    result.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(Some(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;));
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; i in start..=end {
&lt;&#x2F;span&gt;&lt;span&gt;    result.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(Some(i));
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; end &amp;lt; total - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    result.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(None);
&lt;&#x2F;span&gt;&lt;span&gt;    result.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(Some(total));
&lt;&#x2F;span&gt;&lt;span&gt;  } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else if&lt;&#x2F;span&gt;&lt;span&gt; end &amp;lt; total {
&lt;&#x2F;span&gt;&lt;span&gt;    result.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(Some(total));
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  result
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s define two more helper function which will render pagination link and delimiter (like &lt;code&gt;...&lt;&#x2F;code&gt;):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;pagination_link&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;qs&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;TableFilter, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; maud::Markup {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; url = format!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;?sort=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;amp;order=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;amp;page=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&amp;amp;per_page=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, qs.sort, qs.order, i, qs.per_page);
&lt;&#x2F;span&gt;&lt;span&gt;  html! {
&lt;&#x2F;span&gt;&lt;span&gt;    li {
&lt;&#x2F;span&gt;&lt;span&gt;      a href=(url)
&lt;&#x2F;span&gt;&lt;span&gt;        hx-trigger=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;click&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        hx-get=(url)
&lt;&#x2F;span&gt;&lt;span&gt;        hx-target=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;#contacts_table&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        hx-swap=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;outerHTML&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      { (i) }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;pagination_delim&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; maud::Markup {
&lt;&#x2F;span&gt;&lt;span&gt;  html! {
&lt;&#x2F;span&gt;&lt;span&gt;    li {
&lt;&#x2F;span&gt;&lt;span&gt;      span { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And finally we can write pagination function, which will return list of links and delimiters:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;pagination&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;pages&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;qs&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;TableFilter) -&amp;gt; maud::Markup {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; items = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;calc_pagination&lt;&#x2F;span&gt;&lt;span&gt;(qs.page as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;, pages as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  html!(
&lt;&#x2F;span&gt;&lt;span&gt;    nav {
&lt;&#x2F;span&gt;&lt;span&gt;      ul {
&lt;&#x2F;span&gt;&lt;span&gt;        @&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; item in items {
&lt;&#x2F;span&gt;&lt;span&gt;          @&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if let &lt;&#x2F;span&gt;&lt;span&gt;Some(i) = item {
&lt;&#x2F;span&gt;&lt;span&gt;            (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;pagination_link&lt;&#x2F;span&gt;&lt;span&gt;(qs, i as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;          } @&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;            (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;pagination_delim&lt;&#x2F;span&gt;&lt;span&gt;())
&lt;&#x2F;span&gt;&lt;span&gt;          }
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  )
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;index_page&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;req&lt;&#x2F;span&gt;&lt;span&gt;: Request) -&amp;gt; impl IntoResponse {
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;base&lt;&#x2F;span&gt;&lt;span&gt;(html! {
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ..
&lt;&#x2F;span&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; add pagination call after table
&lt;&#x2F;span&gt;&lt;span&gt;		(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;pagination&lt;&#x2F;span&gt;&lt;span&gt;(pages, &amp;amp;qs))
&lt;&#x2F;span&gt;&lt;span&gt;	})
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;partial-html-updates&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#partial-html-updates&quot; aria-label=&quot;Anchor link for: partial-html-updates&quot;&gt;Partial HTML updates&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Before this step, we always replaced the whole page with new HTML content. This can be done without HTMX at all, so what the point of using it? It&#x27;s right, we have very simple layout before. Let&#x27;s make it more complex to show nice feature of HTMX – partial updates.&lt;&#x2F;p&gt;
&lt;p&gt;First of all let&#x27;s move table generation into separate function:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get_contacts_table&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;contacts&lt;&#x2F;span&gt;&lt;span&gt;: Vec&amp;lt;Contact&amp;gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;qs&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;TableFilter, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;pages&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; maud::Markup {
&lt;&#x2F;span&gt;&lt;span&gt;  html! {
&lt;&#x2F;span&gt;&lt;span&gt;  	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; id moved from table to div
&lt;&#x2F;span&gt;&lt;span&gt;  	div id=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;contacts_table&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;	    table {
&lt;&#x2F;span&gt;&lt;span&gt;	      thead {
&lt;&#x2F;span&gt;&lt;span&gt;	        tr {
&lt;&#x2F;span&gt;&lt;span&gt;	          (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ID&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;qs))
&lt;&#x2F;span&gt;&lt;span&gt;	          (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;qs))
&lt;&#x2F;span&gt;&lt;span&gt;	          (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Company&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;qs))
&lt;&#x2F;span&gt;&lt;span&gt;	          (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Email&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;qs))
&lt;&#x2F;span&gt;&lt;span&gt;	          (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;th&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Phone&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;amp;qs))
&lt;&#x2F;span&gt;&lt;span&gt;	        }
&lt;&#x2F;span&gt;&lt;span&gt;	      }
&lt;&#x2F;span&gt;&lt;span&gt;	      tbody {
&lt;&#x2F;span&gt;&lt;span&gt;	        @&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; contact in contacts {
&lt;&#x2F;span&gt;&lt;span&gt;	          tr {
&lt;&#x2F;span&gt;&lt;span&gt;	            td { (contact.id) }
&lt;&#x2F;span&gt;&lt;span&gt;	            td { (contact.name) }
&lt;&#x2F;span&gt;&lt;span&gt;	            td { (contact.company) }
&lt;&#x2F;span&gt;&lt;span&gt;	            td { (contact.email) }
&lt;&#x2F;span&gt;&lt;span&gt;	            td { (contact.phone) }
&lt;&#x2F;span&gt;&lt;span&gt;	          }
&lt;&#x2F;span&gt;&lt;span&gt;	        }
&lt;&#x2F;span&gt;&lt;span&gt;	      }
&lt;&#x2F;span&gt;&lt;span&gt;	    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	    (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;pagination&lt;&#x2F;span&gt;&lt;span&gt;(pages, &amp;amp;qs))
&lt;&#x2F;span&gt;&lt;span&gt;   	}
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we can call this code in any other place and have contacts table. Now let&#x27;s add some navigation and other content to our main page:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;index_page&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;req&lt;&#x2F;span&gt;&lt;span&gt;: Request) -&amp;gt; impl IntoResponse {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; qs = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;parse_table_filter&lt;&#x2F;span&gt;&lt;span&gt;(req);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;(contacts, pages) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_contacts&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span&gt;, &amp;amp;qs);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;base&lt;&#x2F;span&gt;&lt;span&gt;(html! {
&lt;&#x2F;span&gt;&lt;span&gt;    nav {
&lt;&#x2F;span&gt;&lt;span&gt;      ul {
&lt;&#x2F;span&gt;&lt;span&gt;        li { a href=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;dashboard&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Dashboard&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; } }
&lt;&#x2F;span&gt;&lt;span&gt;        li { a href=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Contacts&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; } }
&lt;&#x2F;span&gt;&lt;span&gt;        li { a href=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;settings&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Settings&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; } }
&lt;&#x2F;span&gt;&lt;span&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    h1 { &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Contacts&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;    (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_contacts_table&lt;&#x2F;span&gt;&lt;span&gt;(contacts, &amp;amp;qs, pages))
&lt;&#x2F;span&gt;&lt;span&gt;  })
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Right now in the application we have a simple navigation. But when we interact with the table, a full page will be returned, and the result will look like a nested page in a nested page... This is wrong. Let&#x27;s fix this with HTMX (and this is actually where HTMX comes power).&lt;&#x2F;p&gt;
&lt;p&gt;When browser loads the page it load as regular page with default headers. When request send by HTMX it will set extra headers like &lt;code&gt;HX-Request&lt;&#x2F;code&gt; and &lt;code&gt;HX-Target&lt;&#x2F;code&gt;. We can use this headers to detect which part of HTML should be returned. Let&#x27;s add this code to our &lt;code&gt;index_page&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get_hx_target&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;req&lt;&#x2F;span&gt;&lt;span&gt;: &amp;amp;Request) -&amp;gt; Option&amp;lt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; req.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;headers&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;hx-target&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;) {
&lt;&#x2F;span&gt;&lt;span&gt;    Some(x) =&amp;gt; Some(x.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;to_str&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;unwrap_or_default&lt;&#x2F;span&gt;&lt;span&gt;()),
&lt;&#x2F;span&gt;&lt;span&gt;    None =&amp;gt; None,
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;index_page&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;req&lt;&#x2F;span&gt;&lt;span&gt;: Request) -&amp;gt; impl IntoResponse {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; qs = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;parse_table_filter&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;req);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;(contacts, pages) = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_contacts&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span&gt;, &amp;amp;qs);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;match &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_hx_target&lt;&#x2F;span&gt;&lt;span&gt;(&amp;amp;req) {
&lt;&#x2F;span&gt;&lt;span&gt;    Some(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;contacts_table&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;) =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;get_contacts_table&lt;&#x2F;span&gt;&lt;span&gt;(contacts, &amp;amp;qs, pages).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_response&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;    _ =&amp;gt; {}
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;base&lt;&#x2F;span&gt;&lt;span&gt;(html! {
&lt;&#x2F;span&gt;&lt;span&gt;  	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; ... this part is the same
&lt;&#x2F;span&gt;&lt;span&gt;  })
&lt;&#x2F;span&gt;&lt;span&gt;  .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into_response&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; added into_response() to relax rust type inference
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So in this code we check if &lt;code&gt;hx-target&lt;&#x2F;code&gt; header is present. If not – we return full page. If it&#x27;s present and equal to &lt;code&gt;contacts_table&lt;&#x2F;code&gt; – we return only table. This is how partial updates works in HTMX. We can split page to smaller parts and update it independently.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot;&gt;Conclusion&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;HTMX is good utility for simple application which allows to add some interactivity without writing a lot of JavaScript code. It easy to use and can be integrated with any backend language, because not require any special server-side support. It&#x27;s also very lightweight and can be used in any project without any additional dependencies.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;PS. Source files of this article can be found &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;blog&#x2F;tree&#x2F;main&#x2F;code&#x2F;rust-htmx-table-sorting&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How to get macOS power metrics with Rust?</title>
        <published>2024-08-13T00:00:00+00:00</published>
        <updated>2024-08-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/powermetrics-macos/"/>
        <id>https://vladkens.cc/powermetrics-macos/</id>
        
        <content type="html" xml:base="https://vladkens.cc/powermetrics-macos/">&lt;p&gt;In this post, I’m going to talk about how &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&quot;&gt;macmon&lt;&#x2F;a&gt; works, specifically where it gets system metrics.&lt;&#x2F;p&gt;
&lt;p&gt;MacOS has a built-in &lt;code&gt;powermetics&lt;&#x2F;code&gt; utility that can show the current CPU core frequencies, utilisation, and power consumption. This program should take these values from the system somewhere. So the first thing to check is what shared libraries and function calls (symbols) are used.&lt;&#x2F;p&gt;
&lt;p&gt;There are several programs can do this:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;otool&lt;&#x2F;code&gt; — show list of shared libraries&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;nm&lt;&#x2F;code&gt; — see the list of used symbols&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;strings&lt;&#x2F;code&gt; — just prints all strings from a binary file, but it may be useful to understand what is going on in the program.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;&amp;gt; otool -L &#x2F;usr&#x2F;bin&#x2F;powermetrics
&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;usr&#x2F;lib&#x2F;libIOReport.dylib (compatibility version 1.0.0, current version 1.0.0)
&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;usr&#x2F;lib&#x2F;libpmsample.dylib (compatibility version 1.0.0, current version 2.0.0)
&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;usr&#x2F;lib&#x2F;libpmenergy.dylib (compatibility version 1.0.0, current version 2.0.0)
&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;System&#x2F;Library&#x2F;Frameworks&#x2F;IOKit.framework&#x2F;Versions&#x2F;A&#x2F;IOKit (compatibility version 1.0.0, current version 275.0.0)
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; nm -a &#x2F;usr&#x2F;bin&#x2F;powermetrics
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;bin&#x2F;powermetrics (for architecture arm64e):
&lt;&#x2F;span&gt;&lt;span&gt;  ...
&lt;&#x2F;span&gt;&lt;span&gt;  U _IOPMCopyPowerStateInfo
&lt;&#x2F;span&gt;&lt;span&gt;  U _IORegistryEntryCreateCFProperties
&lt;&#x2F;span&gt;&lt;span&gt;  U _IORegistryEntryCreateCFProperty
&lt;&#x2F;span&gt;&lt;span&gt;  U _IORegistryEntryFromPath
&lt;&#x2F;span&gt;&lt;span&gt;  ...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This data provides some starting point. Next I just did a search on Github to see how these libs might have been used in other repositories.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-cpu-gpu-usage&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#getting-cpu-gpu-usage&quot; aria-label=&quot;Anchor link for: getting-cpu-gpu-usage&quot;&gt;Getting CPU &#x2F; GPU Usage&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The first thing I found is that macOS has an &lt;code&gt;IOReport&lt;&#x2F;code&gt; shared library that returns a lot of hardware information. Including it can do sampling and return CPU&#x2F;GPU &amp;amp; energy usage.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;IOReport&lt;&#x2F;code&gt; operates on a subscription basis. It is possible to select interesting data channels (or all available) and perform sampling on it in order to obtain actual metrics. The channel has a group &#x2F; subgroup name (sometimes may not exist). I’m interesting in “Energy Model”, “CPU Stats” &#x2F; “CPU Core Performance States” and “GPU Stats” &#x2F; “GPU Performance States”. These values were found by comparing available channels names with the list of those strings used in &lt;code&gt;powermetrics&lt;&#x2F;code&gt; (&lt;code&gt;strings &#x2F;usr&#x2F;bin&#x2F;powermetrics&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;To subscribe to a channel and receive updates, it is first necessary to get internal channel struct as &lt;code&gt;CFDictionary&lt;&#x2F;code&gt; using &lt;code&gt;IOReportCopyChannelsInGroup&lt;&#x2F;code&gt; and merge all the dicts into one using &lt;code&gt;IOReportMergeChannels&lt;&#x2F;code&gt;. Then merged dictionary can be used to create an subscription using &lt;code&gt;IOReportCreateSubscription&lt;&#x2F;code&gt;. Once subscription object obtained, updates can be received with &lt;code&gt;IOReportCreateSamples&lt;&#x2F;code&gt; and &lt;code&gt;IOReportCreateSamplesDelta&lt;&#x2F;code&gt;. All together it looks something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; simplified code without error handling
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::ptr::null;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; channels = vec![];
&lt;&#x2F;span&gt;&lt;span&gt;channels.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(IOReportCopyChannelsInGroup(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Energy Model&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;null&lt;&#x2F;span&gt;&lt;span&gt;(), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;));
&lt;&#x2F;span&gt;&lt;span&gt;channels.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(IOReportCopyChannelsInGroup(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CPU Stats&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CPU Core Performance States&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;));
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; chan = channels[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; i in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;..channels.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;  IOReportMergeChannels(chan, channels[i], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;null&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; size = CFDictionaryGetCount(chan);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; chan = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, size, chan);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; subs: MaybeUninit&amp;lt;CFMutableDictionaryRef&amp;gt; = MaybeUninit::uninit();
&lt;&#x2F;span&gt;&lt;span&gt;IOReportCreateSubscription(std::ptr::null(), chan, s.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;as_mut_ptr&lt;&#x2F;span&gt;&lt;span&gt;(), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, std::ptr::null());
&lt;&#x2F;span&gt;&lt;span&gt;subs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;assume_init&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; sample1 = IOReportCreateSamples(subs, chan, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;null&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;std::thread::sleep(std::time::Duration::from_millis(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;)); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; 100ms
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; sample2 = IOReportCreateSamples(subs, chan, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;null&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; rs = IOReportCreateSamplesDelta(sample1, sample2, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;null&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;CFShow(rs);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; rs is CFDictionary, so we can read metrics by keys from it
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The basic dict functions are exported from &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;core-foundation&quot;&gt;core_foundation&lt;&#x2F;a&gt; crate. &lt;code&gt;IOReport&lt;&#x2F;code&gt; functions are C-bindings to a private macOS API:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;link&lt;&#x2F;span&gt;&lt;span&gt;(name = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;IOReport&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, kind = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;dylib&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;extern &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;C&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;IOReportCopyChannelsInGroup&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;: CFStringRef, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;: CFStringRef, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; CFDictionaryRef;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;IOReportMergeChannels&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;: CFDictionaryRef, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;: CFDictionaryRef, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span&gt;: CFTypeRef);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;IOReportCreateSubscription&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;: CVoidRef, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;: CFMutableDictionaryRef, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*mut&lt;&#x2F;span&gt;&lt;span&gt; CFMutableDictionaryRef, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;d&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;: CFTypeRef) -&amp;gt; IOReportSubscriptionRef;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;IOReportCreateSamples&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;: IOReportSubscriptionRef, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;: CFMutableDictionaryRef, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;: CFTypeRef) -&amp;gt; CFDictionaryRef;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;IOReportCreateSamplesDelta&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;: CFDictionaryRef, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;: CFDictionaryRef, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;c&lt;&#x2F;span&gt;&lt;span&gt;: CFTypeRef) -&amp;gt; CFDictionaryRef;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Full implementation can be found &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&#x2F;blob&#x2F;v0.2.2&#x2F;src&#x2F;sources.rs#L478&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note: For CPU I get values separately for each core. In general, there is also a group “CPU Complex Performance States” to get values for the whole cluster at once, but the group results sometimes show 100% load of the cluster, when in reality there is no load. This is caused by some internal bug. For GPU there is no information for each core separately, so the load information is obtained for the whole GPU at once — good luck no errors were noticed.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;parsing-cpu-gpu-usage&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#parsing-cpu-gpu-usage&quot; aria-label=&quot;Anchor link for: parsing-cpu-gpu-usage&quot;&gt;Parsing CPU &#x2F; GPU Usage&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;IOReportCreateSamplesDelta&lt;&#x2F;code&gt; returns an object with one &lt;code&gt;IOReportChannels&lt;&#x2F;code&gt; field, which containts array of metrics objects. Each metrics object have &lt;code&gt;group&lt;&#x2F;code&gt; and &lt;code&gt;subgroup&lt;&#x2F;code&gt; (on which subscription was created), and extra fields: &lt;code&gt;channel&lt;&#x2F;code&gt; name, value &lt;code&gt;unit&lt;&#x2F;code&gt; and &lt;code&gt;value&lt;&#x2F;code&gt; itself.&lt;&#x2F;p&gt;
&lt;p&gt;The values for “CPU Stats” &#x2F; “GPU Stats” are returned in array of tuples (string, int):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;string: frequency level name (first always IDLE)&lt;&#x2F;li&gt;
&lt;li&gt;int: time been on this level (should be in nanoseconds, but not sure)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In general, internally CPU can work at different frequencies and voltages. The values of these frequencies are known in advance and are always the same. Under load CPU works at higher levels (higher frequency, higher voltage). During idle work it constantly jumps between modes (in any case OS always has some background activity). Simple tasks are mostly executed on E-cluster, more complex ones are switched to P-cluster.&lt;&#x2F;p&gt;
&lt;p&gt;Each cluster has different DVFS config (Dynamic Voltage and Frequency Scaling), but all cores within same cluster uses same DVFS config. Same approach is used for GPUs.&lt;&#x2F;p&gt;
&lt;p&gt;Usually GUI interfaces show single number as current core frequency, but in reality it is calculated as average of time each core work on DVFS level. So the average frequency of a core can be calculated like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; predefined DVFS values for E-cluster
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; frequencies = [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;600&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;912&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1284&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1752&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2004&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2256&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2424&lt;&#x2F;span&gt;&lt;span&gt;]; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; 7 items
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; time was on each level (first value is idle)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; residencies = [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;17563069&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5787276&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;156965&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;419037&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;100647&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;106031&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;41735&lt;&#x2F;span&gt;&lt;span&gt;]; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; 8 items
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; total_time = residencies.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span&gt;().sum::&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;();
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; usage_time = residencies.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;skip&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;).sum::&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; freq = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; i in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;..frequencies.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; percent = residencies[i + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;] as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64 &lt;&#x2F;span&gt;&lt;span&gt;&#x2F; usage_time as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt; freq += percent * frequencies[i] as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f64&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;println!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;E-cluster freq: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{:.2}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; MHz&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, freq);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;DVFS values for target system can be read from &lt;code&gt;AppleARMIODevice&lt;&#x2F;code&gt;. Full code can be found &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&#x2F;blob&#x2F;v0.2.2&#x2F;src&#x2F;sources.rs#L459&quot;&gt;here&lt;&#x2F;a&gt;. For M1&#x2F;M2&#x2F;M3 processors looks names are: &lt;code&gt;voltage-states1-sram&lt;&#x2F;code&gt; for E-Cluster, &lt;code&gt;voltage-states5-sram&lt;&#x2F;code&gt; for P-Cluster and &lt;code&gt;voltage-states9&lt;&#x2F;code&gt; for GPU. For Max &#x2F; Ultra chips is also exists &lt;code&gt;voltage-states11-sram&lt;&#x2F;code&gt; or something like this, because this chips have two or more P-Clusters but fortunately this values are same for all clusters of same group (at least for now).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;parsing-energy-usage&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#parsing-energy-usage&quot; aria-label=&quot;Anchor link for: parsing-energy-usage&quot;&gt;Parsing Energy Usage&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In the channel earlier, we also asked for metrics for the “Energy Model” group. These are easier to read because it’s just a number. Value unit can be &lt;code&gt;mJ &#x2F; uJ &#x2F; nJ&lt;&#x2F;code&gt;, so it just needs to be converted to Watts. This is easily done using the formula: &lt;code&gt;P(W) = E(J) &#x2F; t(s)&lt;&#x2F;code&gt;, where &lt;code&gt;s&lt;&#x2F;code&gt; is sampling time. Full code &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&#x2F;blob&#x2F;v0.2.2&#x2F;src&#x2F;metrics.rs#L249&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; joules_raw = IOReportSimpleGetIntegerValue(metric_dict, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;) as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f32&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; joules = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; metric_unit.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;as_str&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mJ&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; =&amp;gt; joules_raw &#x2F; 1e3f32,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;uJ&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; =&amp;gt; joules_raw &#x2F; 1e6f32,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;nJ&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; =&amp;gt; joules_raw &#x2F; 1e9f32,
&lt;&#x2F;span&gt;&lt;span&gt;  _ =&amp;gt; Err(format!(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Unknown energy unit: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, metric_unit).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;into&lt;&#x2F;span&gt;&lt;span&gt;()),
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; sec = (duration as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f32 &lt;&#x2F;span&gt;&lt;span&gt;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1000.0&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; watts = joules &#x2F; sec;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;getting-ram-usage&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#getting-ram-usage&quot; aria-label=&quot;Anchor link for: getting-ram-usage&quot;&gt;Getting RAM Usage&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Getting RAM &#x2F; SWAP usage is done via &lt;code&gt;libc&lt;&#x2F;code&gt; in principle I think similar to any UNIX-like system. Nothing specific here, except to figure out how to calculate the value in bytes, since internally memory is measured in pages.&lt;&#x2F;p&gt;
&lt;p&gt;MacOS uses the &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;opensource.apple.com&#x2F;source&#x2F;xnu&#x2F;xnu-1456.1.26&#x2F;osfmk&#x2F;mach&#x2F;vm_statistics.h.auto.html#:~:text=struct%20vm_statistics64&quot;&gt;&lt;code&gt;vm_statistics64&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; structure, which has quite a few fields. By experimentation I found a value that is similar to what Activity Monitor shows. To get current memory &lt;code&gt;host_statistics64&lt;&#x2F;code&gt; need to be called. For total memory available and SWAP info &lt;code&gt;sysconf&lt;&#x2F;code&gt; call is enough. Full code can be found &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&#x2F;blob&#x2F;v0.2.2&#x2F;src&#x2F;sources.rs#L291&quot;&gt;here&lt;&#x2F;a&gt;. Short example with &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;libc&quot;&gt;libc&lt;&#x2F;a&gt; crate:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; count: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span&gt;= libc::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;HOST_VM_INFO64_COUNT &lt;&#x2F;span&gt;&lt;span&gt;as _;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; stats = std::mem::zeroed::&amp;lt;libc::vm_statistics64&amp;gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;libc::host_statistics64(
&lt;&#x2F;span&gt;&lt;span&gt;  libc::mach_host_self(),
&lt;&#x2F;span&gt;&lt;span&gt;  libc::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;HOST_VM_INFO64&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; stats as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*mut &lt;&#x2F;span&gt;&lt;span&gt;_ as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*mut &lt;&#x2F;span&gt;&lt;span&gt;_, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; cast to void (untyped) pointer
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; count,
&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; page_size_kb = libc::sysconf(libc::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;_SC_PAGESIZE&lt;&#x2F;span&gt;&lt;span&gt;) as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; usage = page_size_kb * (
&lt;&#x2F;span&gt;&lt;span&gt;  + stats.active_count as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64
&lt;&#x2F;span&gt;&lt;span&gt;  + stats.inactive_count as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64
&lt;&#x2F;span&gt;&lt;span&gt;  + stats.wire_count as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64
&lt;&#x2F;span&gt;&lt;span&gt;  + stats.speculative_count as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64
&lt;&#x2F;span&gt;&lt;span&gt;  + stats.compressor_page_count as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64
&lt;&#x2F;span&gt;&lt;span&gt;  - stats.purgeable_count as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64
&lt;&#x2F;span&gt;&lt;span&gt;  - stats.external_page_count as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;getting-temperature-values&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#getting-temperature-values&quot; aria-label=&quot;Anchor link for: getting-temperature-values&quot;&gt;Getting Temperature Values&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This appeared to be the most complicated part of the program. Initially I wanted to get values for each core separately and show them in a separate tab in the interface. On macOS there are GUI programs (Stats, Macs Fan Control) that can do this, but after a detailed study I realised that the values in these programs are shown by guessing which sensor is responsible for which core.&lt;&#x2F;p&gt;
&lt;p&gt;Temperature value can be obtained from two places: IOHID for M1 on macOS 12–13 and SMC for M1&#x2F;M2&#x2F;M3 on macOS 14–15.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;IOHID&lt;&#x2F;code&gt; approach is simpler — it’s just a function call that returns a &lt;code&gt;CFDictionary&lt;&#x2F;code&gt; with values. There seems only &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;freedomtan&#x2F;sensors&#x2F;blob&#x2F;master&#x2F;sensors&#x2F;sensors.m&quot;&gt;one person in open-source&lt;&#x2F;a&gt; who understands how it works, because all other repositories I found referenced it.&lt;&#x2F;p&gt;
&lt;p&gt;SMC (System Management Controller) is more complicated. It works through something similar to RPC calls with large structures where fields are optionally filled in depending on which RPC method called. SMC looks like a more classic approach, but it looks like Apple didn’t have time to implement all the functionality during migration to ARM architecture. To make &lt;code&gt;macmon&lt;&#x2F;code&gt; works everywhere, I had to implement both approaches.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;IOHID&lt;&#x2F;code&gt; implementation can be found &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&#x2F;blob&#x2F;v0.2.2&#x2F;src&#x2F;sources.rs#L603&quot;&gt;here&lt;&#x2F;a&gt;, there is really nothing to talk about technically, except that the parameter values are found &quot;magically&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;In SMC, it is possible to obtain a sensor’s value using a key. The key itself uses FourCC notation, which is essentially &lt;code&gt;int32&lt;&#x2F;code&gt; but appears human-readable in code (for example, &lt;code&gt;Tp01 -&amp;gt; 0x54703031&lt;&#x2F;code&gt;, &lt;code&gt;Tp02 -&amp;gt; 0x54703032&lt;&#x2F;code&gt;, etc.). This key is used to obtain &lt;code&gt;KeyInfo&lt;&#x2F;code&gt;, from which &lt;code&gt;KeyData&lt;&#x2F;code&gt; can be retrieved. Therefore, to get the sensor value, two RPC calls are needed, which is inefficient and costly. Hence, it is necessary to cache the &lt;code&gt;KeyInfo&lt;&#x2F;code&gt; value beforehand.&lt;&#x2F;p&gt;
&lt;p&gt;The SMC initialisation process looks like: obtain all possible keys using the special key &lt;code&gt;#KEY&lt;&#x2F;code&gt; (&lt;code&gt;0x234b4559&lt;&#x2F;code&gt;), then filter out only those &lt;code&gt;KeyInfo&lt;&#x2F;code&gt; that start with &lt;code&gt;Tp&lt;&#x2F;code&gt; (CPU related) and &lt;code&gt;Tg&lt;&#x2F;code&gt; (GPU related), and then make requests only to them – resulting in one RPC call per sensor.&lt;&#x2F;p&gt;
&lt;p&gt;Since I do not know which sensors correspond to which core or other sensors on the chip, the program simply calculates average of all values per type.&lt;&#x2F;p&gt;
&lt;p&gt;SMC implementation can be found &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&#x2F;blob&#x2F;v0.2.2&#x2F;src&#x2F;sources.rs#L752&quot;&gt;here&lt;&#x2F;a&gt; (utility to perform RPC calls), &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&#x2F;blob&#x2F;v0.2.2&#x2F;src&#x2F;metrics.rs#L83&quot;&gt;here&lt;&#x2F;a&gt; (initialisation) and &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&#x2F;blob&#x2F;v0.2.2&#x2F;src&#x2F;metrics.rs#L147&quot;&gt;here&lt;&#x2F;a&gt; (actual metrics gathering).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;combine-all-together&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#combine-all-together&quot; aria-label=&quot;Anchor link for: combine-all-together&quot;&gt;Combine all together&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;There’s nothing special about this part. Once per second, the current metric values are obtained from sources described above. The only thing worth noting is that SMC is used by default, if its value is not available, then IOHID is used (fallback for M1 on macOS 13). Then these values are combined into a single structure and return to caller.&lt;&#x2F;p&gt;
&lt;p&gt;Then these values are aggregated in the &quot;frontend&quot; code and output to the console using &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;ratatui&quot;&gt;ratatui&lt;&#x2F;a&gt; crate or in plain text in raw mode. But this is already a material for a separate article.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;You can try &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&quot;&gt;macmon&lt;&#x2F;a&gt; with Homebrew:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span&gt; install vladkens&#x2F;tap&#x2F;macmon
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>macmon – Mac Usage Monitor in Terminal</title>
        <published>2024-08-06T00:00:00+00:00</published>
        <updated>2024-08-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/macmon/"/>
        <id>https://vladkens.cc/macmon/</id>
        
        <content type="html" xml:base="https://vladkens.cc/macmon/">&lt;p&gt;&lt;img src=&quot;&#x2F;macmon-1.png&quot; alt=&quot;macmon preview&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;When MacBook moved to ARM architecture (M1 processor), old system APIs stopped working and with them existing monitoring tools. However, macOS has a built-in console utility called &lt;code&gt;powermetrics&lt;&#x2F;code&gt;. It can show real-time resource consumption, but it does it in plain text.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;asitop&lt;&#x2F;code&gt; is the first utility that allows users to view resource and energy consumption visually in a terminal. But it works on top of &lt;code&gt;powermetrics&lt;&#x2F;code&gt; which requires &lt;code&gt;sudo&lt;&#x2F;code&gt; to work. The program is written in Python and has compatibility issues with new M-processors.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;macmon&lt;&#x2F;code&gt; attempts to solve these issues. Coded in Rust as a single binary file it uses an undocumented Apple API (the same API that uses powermetrics, but doesn’t require sudo) to get metrics on system utilization, power consumption and temperature.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;installation&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#installation&quot; aria-label=&quot;Anchor link for: installation&quot;&gt;Installation&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span&gt; install vladkens&#x2F;tap&#x2F;macmon
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;features&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#features&quot; aria-label=&quot;Anchor link for: features&quot;&gt;Features&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;No Sudo Required&lt;&#x2F;em&gt;: Run seamlessly without administrative privileges.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Real-Time Metrics&lt;&#x2F;em&gt;: Monitor CPU&#x2F;GPU&#x2F;ANE power usage live.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Detailed Utilisation&lt;&#x2F;em&gt;: Track CPU usage per cluster and RAM&#x2F;Swap usage.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Historical Data: View&lt;&#x2F;em&gt; historical charts with average and max values.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Customizable Interface&lt;&#x2F;em&gt;: Switch between six color variants.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Compact Design&lt;&#x2F;em&gt;: Fits neatly in a small terminal window.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Built with Rust&lt;&#x2F;em&gt;: Ensuring performance and reliability.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;interface-overview&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#interface-overview&quot; aria-label=&quot;Anchor link for: interface-overview&quot;&gt;Interface Overview&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;macmon-2.webp&quot; alt=&quot;macmon&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The top line shows the chip model, number of Effective (E) and Performance (P) cores, number of GPU cores, and RAM.&lt;&#x2F;p&gt;
&lt;p&gt;The second line shows the chart of E and P cluster utilization of the CPU. MacOS uses E-cores for normal tasks, but when something complex needs to be done, process switches to P-cores.&lt;&#x2F;p&gt;
&lt;p&gt;The third line shows memory usage and GPU loading (during gaming, video processing or LLM running 😈).&lt;&#x2F;p&gt;
&lt;p&gt;And finally, the fourth line, the most interesting one, shows the power consumption for compute tasks, by system in general and separately for CPU, GPU and ANE (Apple Neural Engine). It also shows the average temperature of CPU and GPU.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;code&gt;macmon&lt;&#x2F;code&gt; is an open-source program. You can view, star, request features or report bugs on &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;macmon&quot;&gt;Github&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>REST API Deployment on AWS Lambda with Terraform (2023)</title>
        <published>2023-10-12T00:00:00+00:00</published>
        <updated>2023-10-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/aws-python-lambda/"/>
        <id>https://vladkens.cc/aws-python-lambda/</id>
        
        <content type="html" xml:base="https://vladkens.cc/aws-python-lambda/">&lt;p&gt;In this article I will show the way how to deploy AWS Lambda using Terraform, with support for code updates in a single workflow.&lt;&#x2F;p&gt;
&lt;p&gt;The problem with AWS Lambda is that at the time of its creation we need to have prepared code in zip archive or Docker image uploaded to ECR, unlike ECS &#x2F; Kubernetes service, where we just specify the path to the repository, which can be empty at the creation stage. So to make an AWS Lambda deploy using Terraform we will need to prepare the code in the same Terraform recipe.&lt;&#x2F;p&gt;
&lt;p&gt;In this article I will use the Docker image as source for AWS Lambda, as it is essentially the only one normal way to run any complex applications in Lambda that have external dependencies (libraries). There is a way to package the dependencies in a zip archive too, but if the architecture of the computer where the dependencies were built is different from the one where AWS Lambda runs, there will be problems. That’s why Docker is the most clear and reliable option.&lt;&#x2F;p&gt;
&lt;p&gt;So this article will explore the creation of such resources:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Simple HTTP server on Python with FastAPI&lt;&#x2F;li&gt;
&lt;li&gt;Docker image to that application&lt;&#x2F;li&gt;
&lt;li&gt;Creating ECR storage&lt;&#x2F;li&gt;
&lt;li&gt;Build &amp;amp; push Docker image in Terraform file (null_resource)&lt;&#x2F;li&gt;
&lt;li&gt;Creating AWS Lambda&lt;&#x2F;li&gt;
&lt;li&gt;Creating access to Lambda from public url&lt;&#x2F;li&gt;
&lt;li&gt;Updating Lambda on code change&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;preparation&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#preparation&quot; aria-label=&quot;Anchor link for: preparation&quot;&gt;Preparation&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;As usual, we start our work by creating a new project and declaring terraform dependencies:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span&gt; lambda-demo; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span&gt; lambda-demo; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;touch&lt;&#x2F;span&gt;&lt;span&gt; main.tf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Describe Terraform dependencies in &lt;code&gt;main.tf&lt;&#x2F;code&gt; file&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span&gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  required_providers {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;aws &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;source &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;hashicorp&#x2F;aws&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;5.17.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;provider &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;profile &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;default&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;region  &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;us-east-1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;creating-http-application-with-fastapi&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#creating-http-application-with-fastapi&quot; aria-label=&quot;Anchor link for: creating-http-application-with-fastapi&quot;&gt;Creating HTTP application with FastAPI&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s create subfolder for our code and create 3 files:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span&gt; code; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;touch&lt;&#x2F;span&gt;&lt;span&gt; code&#x2F;app.py code&#x2F;requirements.txt code&#x2F;Dockerfile
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, in the &lt;code&gt;app.py&lt;&#x2F;code&gt; file add the application code:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;os
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;uvicorn
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;fastapi &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;FastAPI
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;mangum &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;Mangum
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;app = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;FastAPI&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@app.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;index&lt;&#x2F;span&gt;&lt;span&gt;():
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Hello, from AWS Lambda!&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;handler = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Mangum&lt;&#x2F;span&gt;&lt;span&gt;(app, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;lifespan&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;off&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;__name__ == &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;__main__&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;:
&lt;&#x2F;span&gt;&lt;span&gt;    uvicorn_app = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;{os.path.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;basename&lt;&#x2F;span&gt;&lt;span&gt;(__file__).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;removesuffix&lt;&#x2F;span&gt;&lt;span&gt;(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.py&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;)}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;:app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    uvicorn.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;(uvicorn_app, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;host&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.0.0.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;port&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8000&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;reload&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This code runs the &lt;code&gt;FastAPI&lt;&#x2F;code&gt; service, so we can write basically as much complex API as we want. &lt;code&gt;Mangum&lt;&#x2F;code&gt; is a wrapper for the Lambda API, it does all the request processing logic in Lambda internally, allowing &lt;code&gt;FastAPI&lt;&#x2F;code&gt; to work normally. The code in the &lt;code&gt;__name__ == &quot;__main__&quot;&lt;&#x2F;code&gt; section is needed to run the application during development — we can write our API locally as usual.&lt;&#x2F;p&gt;
&lt;p&gt;The following library should be added to &lt;code&gt;requirements.txt&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;fastapi==0.103.2
&lt;&#x2F;span&gt;&lt;span&gt;mangum==0.17.0
&lt;&#x2F;span&gt;&lt;span&gt;uvicorn==0.23.2
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And finally the &lt;code&gt;Dockerfile&lt;&#x2F;code&gt; to build an image for our application:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;Dockerfile&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-Dockerfile &quot;&gt;&lt;code class=&quot;language-Dockerfile&quot; data-lang=&quot;Dockerfile&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; public.ecr.aws&#x2F;lambda&#x2F;python:3.11
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;ENV &lt;&#x2F;span&gt;&lt;span&gt;PYTHONUNBUFFERED=1
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; requirements.txt .&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;pip3 install -r requirements.txt
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; app.py .&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;CMD [ &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;app.handler&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; ]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;creating-ecr&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#creating-ecr&quot; aria-label=&quot;Anchor link for: creating-ecr&quot;&gt;Creating ECR&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;We have the application ready, now we need to run it in AWS Lambda. First of all, we need to create a resource for ECR image. All the work below continues in the &lt;code&gt;main.tf&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ECR ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_ecr_repository&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name                 &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;lambda-api&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;image_tag_mutability &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;MUTABLE&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;force_delete         &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  image_scanning_configuration {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scan_on_push &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;build-push-docker-image&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#build-push-docker-image&quot; aria-label=&quot;Anchor link for: build-push-docker-image&quot;&gt;Build &amp;amp; Push Docker image&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The next step is to build the image directly in the Terraform recipe. For this purpose &lt;code&gt;null_resource&lt;&#x2F;code&gt; will be used.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- Build &amp;amp; push image ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;locals&lt;&#x2F;span&gt;&lt;span&gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;repo_url &lt;&#x2F;span&gt;&lt;span&gt;= aws_ecr_repository.api.repository_url
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;null_resource&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;image&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;triggers &lt;&#x2F;span&gt;&lt;span&gt;= {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;hash &lt;&#x2F;span&gt;&lt;span&gt;= md5(join(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, [for x in fileset(&amp;quot;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.&#x2F;code&#x2F;{*.py,*.txt,Dockerfile}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;) : filemd5(x)]))
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;provisioner &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;local-exec&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;command &lt;&#x2F;span&gt;&lt;span&gt;= &amp;lt;&amp;lt;EOF
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;      aws ecr get-login-password | docker login --username AWS --password-stdin ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.repo_url}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;      docker build --platform linux&#x2F;amd64 -t ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.repo_url}:latest .&#x2F;code
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;      docker push ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.repo_url}:latest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;    EOF
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;data &amp;quot;aws_ecr_image&amp;quot; &amp;quot;latest&amp;quot; {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  repository_name = aws_ecr_repository.api.name
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  image_tag       = &amp;quot;latest&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;  depends_on      = [null_resource.image]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The local-exec part is a classic bash script that logs into ECR, builds and flushes the image. We just wrote it in a Terraform file directly.&lt;&#x2F;p&gt;
&lt;p&gt;The more interesting part is the triggers. It is needed to rebuild the image every time the files in the code folder are changed. The files are selected by mask, so if you need other extensions you should add them to the list.&lt;&#x2F;p&gt;
&lt;p&gt;And the last block is to get information about the last loaded image in ECR. We will need this next to update AWS Lambda.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;creating-lambda-resource&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#creating-lambda-resource&quot; aria-label=&quot;Anchor link for: creating-lambda-resource&quot;&gt;Creating Lambda resource&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;As is typical in AWS, we need permissions to perform various actions. Lambda is no exception and needs a separate role as well. Let’s create a new role with access to Lambda functions and the ability to write logs.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- IAM Role ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_iam_role&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;lambda&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;lambda&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;assume_role_policy &lt;&#x2F;span&gt;&lt;span&gt;= jsonencode({
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;2012-10-17&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Statement &lt;&#x2F;span&gt;&lt;span&gt;= [{
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Effect    &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Allow&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Action    &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sts:AssumeRole&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Principal &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Service &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;lambda.amazonaws.com&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;    }]
&lt;&#x2F;span&gt;&lt;span&gt;  })
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_iam_role_policy_attachment&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;lambda_logs&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;role       &lt;&#x2F;span&gt;&lt;span&gt;= aws_iam_role.lambda.name
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;policy_arn &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;arn:aws:iam::aws:policy&#x2F;service-role&#x2F;AWSLambdaBasicExecutionRole&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, we create a resource for the Lambda function:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- Lambda ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_cloudwatch_log_group&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name              &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;aws&#x2F;lambda&#x2F;api&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;retention_in_days &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;14
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_lambda_function&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;function_name    &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;role             &lt;&#x2F;span&gt;&lt;span&gt;= aws_iam_role.lambda.arn
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;image_uri        &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${aws_ecr_repository.api.repository_url}:latest&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;package_type     &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Image&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;source_code_hash &lt;&#x2F;span&gt;&lt;span&gt;= trimprefix(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;.aws_ecr_image.latest.id, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sha256:&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;timeout          &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  environment {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;variables &lt;&#x2F;span&gt;&lt;span&gt;= {}
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;depends_on &lt;&#x2F;span&gt;&lt;span&gt;= [
&lt;&#x2F;span&gt;&lt;span&gt;    null_resource.image,
&lt;&#x2F;span&gt;&lt;span&gt;    aws_iam_role_policy_attachment.lambda_logs,
&lt;&#x2F;span&gt;&lt;span&gt;    aws_cloudwatch_log_group.api,
&lt;&#x2F;span&gt;&lt;span&gt;  ]
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;lambda-public-endpoint&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#lambda-public-endpoint&quot; aria-label=&quot;Anchor link for: lambda-public-endpoint&quot;&gt;Lambda public endpoint&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Finally we need to create public endpoint. CORS block required to access API from browser. In this article all values is wildcard, but you can change it as your requirements, like: &lt;code&gt;allow_origins = [&quot;https:&#x2F;&#x2F;my-domain.com&quot;]&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- Lambda Endpoint ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_lambda_function_url&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;function_name      &lt;&#x2F;span&gt;&lt;span&gt;= aws_lambda_function.api.function_name
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;authorization_type &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;NONE&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  cors {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;allow_credentials &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;allow_origins     &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;allow_methods     &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;allow_headers     &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;date&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;keep-alive&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;expose_headers    &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;keep-alive&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;date&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;max_age           &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;86400
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;output &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;api_url&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value &lt;&#x2F;span&gt;&lt;span&gt;= aws_lambda_function_url.api.function_url
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;deploying&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#deploying&quot; aria-label=&quot;Anchor link for: deploying&quot;&gt;Deploying&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Initialise terraform and apply the configuration:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span&gt; init
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span&gt; validate &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span&gt; apply
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once this is complete, we will see a link to AWS Lambda:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Apply&lt;&#x2F;span&gt;&lt;span&gt; complete! Resources: 7 added, 0 changed, 0 destroyed.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Outputs:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;api_url&lt;&#x2F;span&gt;&lt;span&gt; = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;xxx.lambda-url.us-east-1.on.aws&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s try:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;https &lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span&gt; output&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -raw&lt;&#x2F;span&gt;&lt;span&gt; api_url)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;HTTP&#x2F;1.1&lt;&#x2F;span&gt;&lt;span&gt; 200 OK
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Connection:&lt;&#x2F;span&gt;&lt;span&gt; keep-alive
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Content-Length:&lt;&#x2F;span&gt;&lt;span&gt; 25
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Content-Type:&lt;&#x2F;span&gt;&lt;span&gt; application&#x2F;json
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Date:&lt;&#x2F;span&gt;&lt;span&gt; Thu, 12 Oct 2023 13:19:40 GMT
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;X-Amzn-Trace-Id:&lt;&#x2F;span&gt;&lt;span&gt; root=1-6527e150-3c0aed5e335681cb7e120cde;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sampled&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0;lineage=1da281dc:0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x-amzn-Remapped-content-length:&lt;&#x2F;span&gt;&lt;span&gt; 25
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x-amzn-RequestId:&lt;&#x2F;span&gt;&lt;span&gt; a560d83b-40c4-4c27-a381-0bb630547a4a
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Hello, from AWS Lambda!&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s works!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;updating-code-and-deploy-new-version&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#updating-code-and-deploy-new-version&quot; aria-label=&quot;Anchor link for: updating-code-and-deploy-new-version&quot;&gt;Updating code and deploy new version&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Since we have prepared all the necessary invalidations above, we simply update the &lt;code&gt;app.py&lt;&#x2F;code&gt; file and re-run terraform apply. I’ll just add v2 to the welcome text. Check it:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;aws-python-lambda-cli.png&quot; alt=&quot;terminal screenshot&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;New application version available on same URL!&lt;&#x2F;p&gt;
&lt;p&gt;Note: https is binary from &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;httpie.io&#x2F;&quot;&gt;httpie&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Next, depending on requirements, we can add AWS Lambda to Route53 (so that there is a link to our domain), configure restriction policy. But these are topics for another article. Good luck with your AWS journey!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>AWS ECS Cluster on EC2 with Terraform (2023)</title>
        <published>2023-09-15T00:00:00+00:00</published>
        <updated>2023-09-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/aws-ecs-cluster/"/>
        <id>https://vladkens.cc/aws-ecs-cluster/</id>
        
        <content type="html" xml:base="https://vladkens.cc/aws-ecs-cluster/">&lt;p&gt;This short guide will describe how to create an AWS ECS Cluster on EC2 in 2023. Basically there are already articles and code samples on the Internet, but some products in AWS are becoming obsolete (like Launch Configuration) and Terraform is undergoing API changes. So the purpose of this article is to show how to run ECS Cluster on EC2 with Terraform today.&lt;&#x2F;p&gt;
&lt;p&gt;This article will look at how to create a Terraform configuration to provide such resources:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;VPC with public subnet&lt;&#x2F;li&gt;
&lt;li&gt;Internet Gateway to connect to the global Internet&lt;&#x2F;li&gt;
&lt;li&gt;Security groups for EC2 Node &amp;amp; ECS Service&lt;&#x2F;li&gt;
&lt;li&gt;Auto-scaling group for ECS cluster with Launch Templates&lt;&#x2F;li&gt;
&lt;li&gt;Publish image to ECR&lt;&#x2F;li&gt;
&lt;li&gt;ECS cluster with task and service definition&lt;&#x2F;li&gt;
&lt;li&gt;Load Balancer to public access &amp;amp; scale ECS Service&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;preparation&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#preparation&quot; aria-label=&quot;Anchor link for: preparation&quot;&gt;Preparation&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;To get started, you need to create a new Terraform project. Let’s create new directory and &lt;code&gt;main.tf&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span&gt; ecs-ec2-demo; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span&gt; ecs-ec2-demo; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;touch&lt;&#x2F;span&gt;&lt;span&gt; main.tf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the Terraform file, it is required to declare the necessary dependencies and initialise the project.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span&gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  required_providers {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;aws &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;source &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;hashicorp&#x2F;aws&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;5.17.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;provider &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;profile &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;default&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;region  &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;us-east-1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;creating-a-vpc&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#creating-a-vpc&quot; aria-label=&quot;Anchor link for: creating-a-vpc&quot;&gt;Creating a VPC&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s make a new VPC &amp;amp; two public subnets.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- VPC ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_availability_zones&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;available&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;state &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;available&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;locals&lt;&#x2F;span&gt;&lt;span&gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;azs_count &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;azs_names &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;.aws_availability_zones.available.names
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_vpc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cidr_block           &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;10.10.0.0&#x2F;16&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;enable_dns_hostnames &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;enable_dns_support   &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tags                 &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-vpc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_subnet&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;count                   &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.azs_count
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vpc_id                  &lt;&#x2F;span&gt;&lt;span&gt;= aws_vpc.main.id
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;availability_zone       &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.azs_names[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;count&lt;&#x2F;span&gt;&lt;span&gt;.index]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cidr_block              &lt;&#x2F;span&gt;&lt;span&gt;= cidrsubnet(aws_vpc.main.cidr_block, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10 &lt;&#x2F;span&gt;&lt;span&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;count&lt;&#x2F;span&gt;&lt;span&gt;.index)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;map_public_ip_on_launch &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tags                    &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-public-${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.azs_names[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;count&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.index]}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then create Internet Gateway:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- Internet Gateway ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_internet_gateway&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vpc_id &lt;&#x2F;span&gt;&lt;span&gt;= aws_vpc.main.id
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tags   &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-igw&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_eip&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;count      &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.azs_count
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;depends_on &lt;&#x2F;span&gt;&lt;span&gt;= [aws_internet_gateway.main]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tags       &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-eip-${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.azs_names[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;count&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.index]}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And after it public route table:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- Public Route Table ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_route_table&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vpc_id &lt;&#x2F;span&gt;&lt;span&gt;= aws_vpc.main.id
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tags   &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-rt-public&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  route {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cidr_block &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.0.0.0&#x2F;0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;gateway_id &lt;&#x2F;span&gt;&lt;span&gt;= aws_internet_gateway.main.id
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_route_table_association&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;count          &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt;.azs_count
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;subnet_id      &lt;&#x2F;span&gt;&lt;span&gt;= aws_subnet.public[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;count&lt;&#x2F;span&gt;&lt;span&gt;.index].id
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;route_table_id &lt;&#x2F;span&gt;&lt;span&gt;= aws_route_table.public.id
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now it is possible to run &lt;code&gt;terraform apply&lt;&#x2F;code&gt; and a new VPC with two public subnets will appear in AWS. Each subnet will placed in different Availability Zone (AZ) and have access to the Internet via IGW.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note: Load Balancer requires at least two subnets created in different Availability Zones (AZ).&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;creating-a-scalable-ecs-cluster&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#creating-a-scalable-ecs-cluster&quot; aria-label=&quot;Anchor link for: creating-a-scalable-ecs-cluster&quot;&gt;Creating a scalable ECS Cluster&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The next step is to create a complete ECS Cluster.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ECS Cluster ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_ecs_cluster&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-cluster&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The code above will create an empty cluster, but in order for the cluster to run containers it needs EC2 instances on which it will run these containers.&lt;&#x2F;p&gt;
&lt;p&gt;AWS can automatically create these EC2 instances and scaling them based on load, but for this we need to define Launch Template &amp;amp; Autoscaling Group. To implement this we need to create such resources:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;IAM Role for ECS Node&lt;&#x2F;li&gt;
&lt;li&gt;Security Group (SG) for ECS Node&lt;&#x2F;li&gt;
&lt;li&gt;Launch Template (describes EC2 instance)&lt;&#x2F;li&gt;
&lt;li&gt;Autoscaling Group (AG)&lt;&#x2F;li&gt;
&lt;li&gt;Capacity Provider to connect ECS Cluster &amp;amp; Autoscaling Group&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;iam-role-security-group-for-ecs-ec2-node&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#iam-role-security-group-for-ecs-ec2-node&quot; aria-label=&quot;Anchor link for: iam-role-security-group-for-ecs-ec2-node&quot;&gt;IAM Role &amp;amp; Security Group for ECS EC2 Node&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s start from creating IAM Role for ECS Node:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ECS Node Role ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_iam_policy_document&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_node_doc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  statement {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;actions &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sts:AssumeRole&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;effect  &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Allow&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    principals {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;type        &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Service&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;identifiers &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ec2.amazonaws.com&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_iam_role&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_node_role&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name_prefix        &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-ecs-node-role&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;assume_role_policy &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;.aws_iam_policy_document.ecs_node_doc.json
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_iam_role_policy_attachment&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_node_role_policy&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;role       &lt;&#x2F;span&gt;&lt;span&gt;= aws_iam_role.ecs_node_role.name
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;policy_arn &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;arn:aws:iam::aws:policy&#x2F;service-role&#x2F;AmazonEC2ContainerServiceforEC2Role&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_iam_instance_profile&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_node&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name_prefix &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-ecs-node-profile&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;path        &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;ecs&#x2F;instance&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;role        &lt;&#x2F;span&gt;&lt;span&gt;= aws_iam_role.ecs_node_role.name
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then create simple Security Group for ECS Node which allow outgoing traffic (its required to pull image to start service later)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ECS Node SG ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_security_group&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_node_sg&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name_prefix &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-ecs-node-sg-&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vpc_id      &lt;&#x2F;span&gt;&lt;span&gt;= aws_vpc.main.id
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  egress {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;from_port   &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;to_port     &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;65535
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;protocol    &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;tcp&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cidr_blocks &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.0.0.0&#x2F;0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;launch-template&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#launch-template&quot; aria-label=&quot;Anchor link for: launch-template&quot;&gt;Launch Template&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Next step is to create Launch Template for EC2 Instance.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ECS Launch Template ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_ssm_parameter&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_node_ami&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;aws&#x2F;service&#x2F;ecs&#x2F;optimized-ami&#x2F;amazon-linux-2&#x2F;recommended&#x2F;image_id&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_launch_template&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_ec2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name_prefix            &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-ecs-ec2-&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;image_id               &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;.aws_ssm_parameter.ecs_node_ami.value
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;instance_type          &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;t2.micro&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vpc_security_group_ids &lt;&#x2F;span&gt;&lt;span&gt;= [aws_security_group.ecs_node_sg.id]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  iam_instance_profile { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;arn &lt;&#x2F;span&gt;&lt;span&gt;= aws_iam_instance_profile.ecs_node.arn }
&lt;&#x2F;span&gt;&lt;span&gt;  monitoring { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;enabled &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt; }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;user_data &lt;&#x2F;span&gt;&lt;span&gt;= base64encode(&amp;lt;&amp;lt;-EOF
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;      #!&#x2F;bin&#x2F;bash
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;      echo ECS_CLUSTER=${aws_ecs_cluster.main.name} &amp;gt;&amp;gt; &#x2F;etc&#x2F;ecs&#x2F;ecs.config;
&lt;&#x2F;span&gt;&lt;span&gt;    EOF
&lt;&#x2F;span&gt;&lt;span&gt;  )
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A couple of comments on the code above:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;ecs_node_ami&lt;&#x2F;code&gt; is the recommended image for ECS (but it possible to use another image by passing different &lt;code&gt;ami&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;In &lt;code&gt;user_data&lt;&#x2F;code&gt; you is required to pass ECS cluster name, so AWS can register EC2 instance as node of ECS cluster&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;autoscaling-group&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#autoscaling-group&quot; aria-label=&quot;Anchor link for: autoscaling-group&quot;&gt;Autoscaling Group&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Next step is to create autoscaling group (ASG) and connect it with Launch Template:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ECS ASG ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_autoscaling_group&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name_prefix               &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-ecs-asg-&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vpc_zone_identifier       &lt;&#x2F;span&gt;&lt;span&gt;= aws_subnet.public[*].id
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;min_size                  &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;max_size                  &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;8
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;health_check_grace_period &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;health_check_type         &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;EC2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;protect_from_scale_in     &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  launch_template {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;id      &lt;&#x2F;span&gt;&lt;span&gt;= aws_launch_template.ecs_ec2.id
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;$Latest&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  tag {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key                 &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value               &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-ecs-cluster&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;propagate_at_launch &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  tag {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key                 &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;AmazonECSManaged&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value               &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;propagate_at_launch &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This ASG will create from 2 to 8 instances of EC2 using Launch Template. &lt;code&gt;Name&lt;&#x2F;code&gt; tag is optional and used here just to simplify to recognise instances connected to cluster. &lt;code&gt;AmazonECSManaged&lt;&#x2F;code&gt; tag is required by AWS.&lt;&#x2F;p&gt;
&lt;p&gt;At this point we can run &lt;code&gt;terraform apply&lt;&#x2F;code&gt; again and make sure the ASG is working. AWS should create two EC2 instances. The can be seen at &lt;em&gt;AWS Console &amp;gt; EC2 &amp;gt; Instances&lt;&#x2F;em&gt;. If you manually Terminate any of these instances, AWS will automatically create a new instance to match the configuration of ASG (in our case minimum 2).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;aws-ecs-cluster-1.png&quot; alt=&quot;aws console&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;capacity-provider&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#capacity-provider&quot; aria-label=&quot;Anchor link for: capacity-provider&quot;&gt;Capacity Provider&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The last step is to connect the ECS Cluster to the ASG group so that the cluster can use EC2 instances to deploy containers.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ECS Capacity Provider ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_ecs_capacity_provider&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-ecs-ec2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  auto_scaling_group_provider {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;auto_scaling_group_arn         &lt;&#x2F;span&gt;&lt;span&gt;= aws_autoscaling_group.ecs.arn
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;managed_termination_protection &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;DISABLED&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    managed_scaling {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;maximum_scaling_step_size &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;minimum_scaling_step_size &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;status                    &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ENABLED&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;target_capacity           &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;100
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_ecs_cluster_capacity_providers&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cluster_name       &lt;&#x2F;span&gt;&lt;span&gt;= aws_ecs_cluster.main.name
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;capacity_providers &lt;&#x2F;span&gt;&lt;span&gt;= [aws_ecs_capacity_provider.main.name]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  default_capacity_provider_strategy {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;capacity_provider &lt;&#x2F;span&gt;&lt;span&gt;= aws_ecs_capacity_provider.main.name
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;base              &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;weight            &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;100
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Run &lt;code&gt;terraform apply&lt;&#x2F;code&gt; again and after it we should see Capacity Provider &amp;amp; EC2 instances connect to ECS cluster on &lt;em&gt;AWS Console &amp;gt; ECS &amp;gt; demo-cluster &amp;gt; Infrastructure&lt;&#x2F;em&gt; tab.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;aws-ecs-cluster-2.png&quot; alt=&quot;aws console&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;creating-ecs-service&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#creating-ecs-service&quot; aria-label=&quot;Anchor link for: creating-ecs-service&quot;&gt;Creating ECS Service&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The last step is to run the service on the ECS and configure heath check and autoscaling for it. Plan of Action:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Create Elastic Container Registry (ECR) &amp;amp; push image&lt;&#x2F;li&gt;
&lt;li&gt;Create IAM Role for ECS Task&lt;&#x2F;li&gt;
&lt;li&gt;Create ECS Task Definition&lt;&#x2F;li&gt;
&lt;li&gt;Create Security Group for service&lt;&#x2F;li&gt;
&lt;li&gt;Create ECS Service&lt;&#x2F;li&gt;
&lt;li&gt;Create Load Balancer&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;elastic-container-registry-ecr&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#elastic-container-registry-ecr&quot; aria-label=&quot;Anchor link for: elastic-container-registry-ecr&quot;&gt;Elastic Container Registry (ECR)&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The example will use &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hub.docker.com&#x2F;r&#x2F;strm&#x2F;helloworld-http&#x2F;&quot;&gt;helloword-http&lt;&#x2F;a&gt; server, which we will run in our private ECR.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ECR ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_ecr_repository&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name                 &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;image_tag_mutability &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;MUTABLE&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;force_delete         &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  image_scanning_configuration {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scan_on_push &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;output &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo_app_repo_url&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value &lt;&#x2F;span&gt;&lt;span&gt;= aws_ecr_repository.app.repository_url
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s run &lt;code&gt;terraform apply&lt;&#x2F;code&gt; again. We should see output with repository URL in AWS. Now push helloword-http to ECR.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Get AWS repo url from Terraform outputs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;REPO&lt;&#x2F;span&gt;&lt;span&gt;=$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; output&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --raw&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; demo_app_repo_url)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Login to AWS ECR
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span&gt; ecr get-login-password | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; login&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --username&lt;&#x2F;span&gt;&lt;span&gt; AWS&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --password-stdin &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;REPO
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Pull docker image &amp;amp; push to our ECR
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; pull&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --platform&lt;&#x2F;span&gt;&lt;span&gt; linux&#x2F;amd64 strm&#x2F;helloworld-http:latest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; tag strm&#x2F;helloworld-http:latest $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;REPO&lt;&#x2F;span&gt;&lt;span&gt;:latest
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; push $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;REPO&lt;&#x2F;span&gt;&lt;span&gt;:latest
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After this image should be available in &lt;em&gt;AWS Console &amp;gt; AWS ECR &amp;gt; demo-app&lt;&#x2F;em&gt; and it can be used as source for ECS Task Definition.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note: In case you are using ECS Nodes on ARM processors, use &lt;code&gt;--platform linux&#x2F;arm64&lt;&#x2F;code&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;iam-role-for-ecs-task&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#iam-role-for-ecs-task&quot; aria-label=&quot;Anchor link for: iam-role-for-ecs-task&quot;&gt;IAM Role for ECS Task&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Next required step is to defined IAM roles for ECS task. Roles required to have access ECR, Cloud Watch, etc.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ECS Task Role ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_iam_policy_document&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_task_doc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  statement {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;actions &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sts:AssumeRole&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;effect  &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Allow&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    principals {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;type        &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Service&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;identifiers &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs-tasks.amazonaws.com&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_iam_role&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_task_role&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name_prefix        &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-ecs-task-role&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;assume_role_policy &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;.aws_iam_policy_document.ecs_task_doc.json
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_iam_role&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_exec_role&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name_prefix        &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-ecs-exec-role&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;assume_role_policy &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;.aws_iam_policy_document.ecs_task_doc.json
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_iam_role_policy_attachment&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_exec_role_policy&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;role       &lt;&#x2F;span&gt;&lt;span&gt;= aws_iam_role.ecs_exec_role.name
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;policy_arn &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;arn:aws:iam::aws:policy&#x2F;service-role&#x2F;AmazonECSTaskExecutionRolePolicy&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;cloud-watch-logs&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#cloud-watch-logs&quot; aria-label=&quot;Anchor link for: cloud-watch-logs&quot;&gt;Cloud Watch Logs&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Next small step is to create Cloud Watch logs group to be able to see container logs.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- Cloud Watch Logs ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_cloudwatch_log_group&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name              &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;ecs&#x2F;demo&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;retention_in_days &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;14
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;ecs-task-definition&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ecs-task-definition&quot; aria-label=&quot;Anchor link for: ecs-task-definition&quot;&gt;ECS Task Definition&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;At this point, we simply describe from where and how to launch the docker container.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note: Task Definition is created per AWS account, not per ECS Cluster. So the family name must be unique.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ECS Task Definition ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_ecs_task_definition&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;family             &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;task_role_arn      &lt;&#x2F;span&gt;&lt;span&gt;= aws_iam_role.ecs_task_role.arn
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;execution_role_arn &lt;&#x2F;span&gt;&lt;span&gt;= aws_iam_role.ecs_exec_role.arn
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;network_mode       &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;awsvpc&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cpu                &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;256
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;memory             &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;256
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;container_definitions &lt;&#x2F;span&gt;&lt;span&gt;= jsonencode([{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name         &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;image        &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${aws_ecr_repository.app.repository_url}:latest&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;essential    &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;portMappings &lt;&#x2F;span&gt;&lt;span&gt;= [{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;containerPort &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;80&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;hostPort &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;80&lt;&#x2F;span&gt;&lt;span&gt; }],
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;environment &lt;&#x2F;span&gt;&lt;span&gt;= [
&lt;&#x2F;span&gt;&lt;span&gt;      { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;EXAMPLE&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;example&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span&gt;    ]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;logConfiguration &lt;&#x2F;span&gt;&lt;span&gt;= {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;logDriver &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;awslogs&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;options &lt;&#x2F;span&gt;&lt;span&gt;= {
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;awslogs-region&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;        = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;us-east-1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;awslogs-group&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;         = aws_cloudwatch_log_group.ecs.name,
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;awslogs-stream-prefix&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;  }])
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;ecs-service&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ecs-service&quot; aria-label=&quot;Anchor link for: ecs-service&quot;&gt;ECS Service&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In order for the ECS service to be available within the cluster and have access to the Internet, a new Security Group must be created. &lt;code&gt;ecs_svc&lt;&#x2F;code&gt; allows all incoming and outgoing traffic. The service itself will be inside the subnet, without public ip, so it will not be accessible from the Internet. SG allows access to the service only for VPC network members.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ECS Service ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_security_group&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_task&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name_prefix &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs-task-sg-&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;description &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Allow all traffic within the VPC&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vpc_id      &lt;&#x2F;span&gt;&lt;span&gt;= aws_vpc.main.id
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  ingress {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;from_port   &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;to_port     &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;protocol    &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;-1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cidr_blocks &lt;&#x2F;span&gt;&lt;span&gt;= [aws_vpc.main.cidr_block]
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  egress {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;from_port   &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;to_port     &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;protocol    &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;-1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cidr_blocks &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.0.0.0&#x2F;0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_ecs_service&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name            &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cluster         &lt;&#x2F;span&gt;&lt;span&gt;= aws_ecs_cluster.main.id
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;task_definition &lt;&#x2F;span&gt;&lt;span&gt;= aws_ecs_task_definition.app.arn
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;desired_count   &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  network_configuration {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;security_groups &lt;&#x2F;span&gt;&lt;span&gt;= [aws_security_group.ecs_task.id]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;subnets         &lt;&#x2F;span&gt;&lt;span&gt;= aws_subnet.public[*].id
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  capacity_provider_strategy {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;capacity_provider &lt;&#x2F;span&gt;&lt;span&gt;= aws_ecs_capacity_provider.main.name
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;base              &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;weight            &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;100
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  ordered_placement_strategy {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;type  &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;spread&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;field &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;attribute:ecs.availability-zone&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  lifecycle {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ignore_changes &lt;&#x2F;span&gt;&lt;span&gt;= [desired_count]
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;ordered_placement_strategy&lt;&#x2F;code&gt; will try to make sure that each service instance is equally distributed across Availability Zones. You can use a different placement strategy, read the AWS documentation about it.&lt;&#x2F;p&gt;
&lt;p&gt;If we run &lt;code&gt;terraform apply&lt;&#x2F;code&gt; at this step it will create &amp;amp; run new service. But because this service has no Public IP, we can&#x27;t access to it from public Internet. But service accessible from internal VPC. So if we create a Bastion Host we can ping it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;aws-ecs-cluster-3.png&quot; alt=&quot;aws console&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To make the service available from the public network, as well as to be able to scale the service depending on the load we need to create Load Balancer.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;load-balancer-alb&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#load-balancer-alb&quot; aria-label=&quot;Anchor link for: load-balancer-alb&quot;&gt;Load Balancer (ALB)&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;ALB also needs a Security Group. We will allow any incoming traffic on ports 80 and 443. Next, the ALB will listen on port 80 and forward the traffic to our ECS Service. This is the simplest ALB setup sufficient for this article.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ALB ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_security_group&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;http&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name_prefix &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;http-sg-&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;description &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Allow all HTTP&#x2F;HTTPS traffic from public&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vpc_id      &lt;&#x2F;span&gt;&lt;span&gt;= aws_vpc.main.id
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  dynamic &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ingress&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;for_each &lt;&#x2F;span&gt;&lt;span&gt;= [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;80&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;443&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;    content {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;protocol    &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;tcp&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;from_port   &lt;&#x2F;span&gt;&lt;span&gt;= ingress.value
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;to_port     &lt;&#x2F;span&gt;&lt;span&gt;= ingress.value
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cidr_blocks &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.0.0.0&#x2F;0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  egress {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;protocol    &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;-1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;from_port   &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;to_port     &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cidr_blocks &lt;&#x2F;span&gt;&lt;span&gt;= [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.0.0.0&#x2F;0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_lb&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name               &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;demo-alb&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;load_balancer_type &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;application&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;subnets            &lt;&#x2F;span&gt;&lt;span&gt;= aws_subnet.public[*].id
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;security_groups    &lt;&#x2F;span&gt;&lt;span&gt;= [aws_security_group.http.id]
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_lb_target_group&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name_prefix &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;app-&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;vpc_id      &lt;&#x2F;span&gt;&lt;span&gt;= aws_vpc.main.id
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;protocol    &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;HTTP&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;port        &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;80
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;target_type &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ip&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  health_check {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;enabled             &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;path                &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;port                &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;80
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;matcher             &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;200
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;interval            &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;10
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;timeout             &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;healthy_threshold   &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;unhealthy_threshold &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;3
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_lb_listener&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;http&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;load_balancer_arn &lt;&#x2F;span&gt;&lt;span&gt;= aws_lb.main.id
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;port              &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;80
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;protocol          &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;HTTP&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  default_action {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;type             &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;forward&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;target_group_arn &lt;&#x2F;span&gt;&lt;span&gt;= aws_lb_target_group.app.id
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;output &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;alb_url&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value &lt;&#x2F;span&gt;&lt;span&gt;= aws_lb.main.dns_name
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The output &lt;code&gt;alb_url&lt;&#x2F;code&gt; displays the ALB URL provided by AWS. We can ping this url to prove that ALB is working. If we try to ping &lt;code&gt;alb_url&lt;&#x2F;code&gt; right now it will respond with 503 code — that expected because ALB Target Group is empty right now.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;connect-ecs-service-to-alb&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#connect-ecs-service-to-alb&quot; aria-label=&quot;Anchor link for: connect-ecs-service-to-alb&quot;&gt;Connect ECS Service to ALB&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;At the final stage, we need to update the &lt;code&gt;aws_ecs_service&lt;&#x2F;code&gt; configuration by adding a section with &lt;code&gt;load_balancer&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ECS Service ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_ecs_service&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# ...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;depends_on &lt;&#x2F;span&gt;&lt;span&gt;= [aws_lb_target_group.app]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  load_balancer {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;target_group_arn &lt;&#x2F;span&gt;&lt;span&gt;= aws_lb_target_group.app.arn
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;container_name   &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;container_port   &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;80
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally run &lt;code&gt;terraform apply&lt;&#x2F;code&gt;. ECS Service will be started and we can check it on ALB URL provided by AWS:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;curl &lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span&gt; output&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --raw&lt;&#x2F;span&gt;&lt;span&gt; alb_url) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Hello from ip-10-10-10-XXX
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;curl &lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span&gt; output&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --raw&lt;&#x2F;span&gt;&lt;span&gt; alb_url) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Hello from ip-10-10-11-YYY
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we run CURL multiple times, it should write &quot;Hello from HOSTNAME&quot;, the hostname will be different between calls, indicating that ALB is working and redirecting requests to different copies of the ECS Service.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bonus-ecs-service-auto-scaling&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#bonus-ecs-service-auto-scaling&quot; aria-label=&quot;Anchor link for: bonus-ecs-service-auto-scaling&quot;&gt;Bonus: ECS Service Auto Scaling&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;tf&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tf &quot;&gt;&lt;code class=&quot;language-tf&quot; data-lang=&quot;tf&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# --- ECS Service Auto Scaling ---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_appautoscaling_target&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_target&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;service_namespace  &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scalable_dimension &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs:service:DesiredCount&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;resource_id        &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;service&#x2F;${aws_ecs_cluster.main.name}&#x2F;${aws_ecs_service.app.name}&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;min_capacity       &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;max_capacity       &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_appautoscaling_policy&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_target_cpu&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name               &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;application-scaling-policy-cpu&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;policy_type        &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;TargetTrackingScaling&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;service_namespace  &lt;&#x2F;span&gt;&lt;span&gt;= aws_appautoscaling_target.ecs_target.service_namespace
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;resource_id        &lt;&#x2F;span&gt;&lt;span&gt;= aws_appautoscaling_target.ecs_target.resource_id
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scalable_dimension &lt;&#x2F;span&gt;&lt;span&gt;= aws_appautoscaling_target.ecs_target.scalable_dimension
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  target_tracking_scaling_policy_configuration {
&lt;&#x2F;span&gt;&lt;span&gt;    predefined_metric_specification {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;predefined_metric_type &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ECSServiceAverageCPUUtilization&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;target_value       &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;80
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scale_in_cooldown  &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;300
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scale_out_cooldown &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;300
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;resource &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aws_appautoscaling_policy&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ecs_target_memory&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name               &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;application-scaling-policy-memory&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;policy_type        &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;TargetTrackingScaling&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;resource_id        &lt;&#x2F;span&gt;&lt;span&gt;= aws_appautoscaling_target.ecs_target.resource_id
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scalable_dimension &lt;&#x2F;span&gt;&lt;span&gt;= aws_appautoscaling_target.ecs_target.scalable_dimension
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;service_namespace  &lt;&#x2F;span&gt;&lt;span&gt;= aws_appautoscaling_target.ecs_target.service_namespace
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  target_tracking_scaling_policy_configuration {
&lt;&#x2F;span&gt;&lt;span&gt;    predefined_metric_specification {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;predefined_metric_type &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;ECSServiceAverageMemoryUtilization&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;target_value       &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;80
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scale_in_cooldown  &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;300
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;scale_out_cooldown &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;300
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Here is the end of ECS cluster configuration. Next it is possible to add a domain name, SSL certificate, https termination, routing traffic between different ECS services — but all this is stuff for other articles.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How to still scrape millions of tweets with twscrape</title>
        <published>2023-07-02T00:00:00+00:00</published>
        <updated>2023-07-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/twscrape/"/>
        <id>https://vladkens.cc/twscrape/</id>
        
        <content type="html" xml:base="https://vladkens.cc/twscrape/">&lt;p&gt;Twitter is a great place to gather data and assess various trends. Many analytics teams have used this source for their models.&lt;&#x2F;p&gt;
&lt;p&gt;In February 2023, Twitter set unrealistic prices for its API, giving away crumbs of data for big bucks. Some started using libraries such as snscrape, which used web public APIs. But in April 2023, Twitter closed that option as well — making search only for authorized accounts.&lt;&#x2F;p&gt;
&lt;p&gt;But data can still be collected in much the same way as before using the authorised account approach.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introduction-to-twscrape&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#introduction-to-twscrape&quot; aria-label=&quot;Anchor link for: introduction-to-twscrape&quot;&gt;Introduction to twscrape&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Released in May 2023, it is a tool for scraping data from tweets. It collects data such as user profiles, follower lists and follower lists, likes and retweets, as well as keyword searches.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-started-with-twscrape&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#getting-started-with-twscrape&quot; aria-label=&quot;Anchor link for: getting-started-with-twscrape&quot;&gt;Getting Started with twscrape&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Requirements: Python 3.10 or higher&lt;&#x2F;p&gt;
&lt;h3 id=&quot;installing-twscrape&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#installing-twscrape&quot; aria-label=&quot;Anchor link for: installing-twscrape&quot;&gt;Installing twscrape&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;pip&lt;&#x2F;span&gt;&lt;span&gt; install twscrape
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or development version with latest features:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;pip&lt;&#x2F;span&gt;&lt;span&gt; install git+https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;twscrape.git
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;adding-accounts&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#adding-accounts&quot; aria-label=&quot;Anchor link for: adding-accounts&quot;&gt;Adding accounts&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;twscrape&lt;&#x2F;code&gt; needs Twitter accounts to work. Each account has a rather small limit on the use of APIs, after which some time is no way to make requests through that account. &lt;code&gt;twscrape&lt;&#x2F;code&gt; is designed to switch accounts when one of them is not available. In this way the data flow looks continuous to the user, although in fact the requests come from different accounts internally.&lt;&#x2F;p&gt;
&lt;p&gt;Accounts can be added in two ways, via software API or CLI command. Let’s use the CLI command:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# twscrape add_accounts &amp;lt;file_path&amp;gt; &amp;lt;line_format&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# line_format should have &amp;quot;username&amp;quot;, &amp;quot;password&amp;quot;, &amp;quot;email&amp;quot;, &amp;quot;email_password&amp;quot; tokens
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# tokens delimeter should be same as an file
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;twscrape&lt;&#x2F;span&gt;&lt;span&gt; add_accounts accounts.txt username:password:email:email_password
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;Note: It is possible to register a new account or buy on special websites, e.g. &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kutt.it&#x2F;ueeM5f&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You then have to go through the login procedure to get the tokens to request the API. It’s not a quick process, but it’s needed once after adding new accounts. Then the token is stored in the SQLite database and reused for subsequent queries.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;twscrape&lt;&#x2F;span&gt;&lt;span&gt; login_accounts
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;Note: Not all accounts can pass authorisation because of the antifraud system. You can try logging into these accounts again later.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-twscrape&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#using-twscrape&quot; aria-label=&quot;Anchor link for: using-twscrape&quot;&gt;Using twscrape&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;You can use &lt;code&gt;twscrape&lt;&#x2F;code&gt; in two ways.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Using an CLI (terminal) and receive JSON object&lt;&#x2F;li&gt;
&lt;li&gt;Using Python API (usuful for custom data collection scripts)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;lets-get-some-tweet-details-from-cli&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#lets-get-some-tweet-details-from-cli&quot; aria-label=&quot;Anchor link for: lets-get-some-tweet-details-from-cli&quot;&gt;Lets get some tweet details from CLI:&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;twscrape&lt;&#x2F;span&gt;&lt;span&gt; tweet_details 1674894268912087040
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Result:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; 1674894268912087000,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;id_str&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1674894268912087040&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;twitter.com&#x2F;elonmusk&#x2F;status&#x2F;1674894268912087040&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;date&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;2023-06-30 21:34:46+00:00&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;user&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: 44196397,
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;id_str&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;44196397&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;twitter.com&#x2F;elonmusk&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;username&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;elonmusk&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;displayname&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Elon Musk&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;created&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;2009-06-02 20:12:29+00:00&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;    &#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;_type&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;snscrape.modules.twitter.User&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  },
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;lang&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;en&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;rawContent&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;This platform hit another all-time high in user-seconds last week&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt; ...
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s that simple. The data format is almost the same as it was in snscrape. So if you already have some scripts to process the data, you can continue to use them without too much trouble.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;scrapping-tweets-from-a-text-search-query-by-python-api&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#scrapping-tweets-from-a-text-search-query-by-python-api&quot; aria-label=&quot;Anchor link for: scrapping-tweets-from-a-text-search-query-by-python-api&quot;&gt;Scrapping tweets from a text search query by Python API&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Using the code below, we are scraping 5000 tweets between January 1, 2023, and May 31, 2023, with the keywords &quot;elon musk&quot;. Then printing in console tweet id, tweet author and content.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;asyncio
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;twscrape &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;API&lt;&#x2F;span&gt;&lt;span&gt;, gather
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;twscrape.logger &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;set_log_level
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;async def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;():
&lt;&#x2F;span&gt;&lt;span&gt;    api = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;API&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    q = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;elon musk since:2023-01-01 until:2023-05-31&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;async for &lt;&#x2F;span&gt;&lt;span&gt;tweet &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;api.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;search&lt;&#x2F;span&gt;&lt;span&gt;(q, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;limit&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5000&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(tweet.id, tweet.user.username, tweet.rawContent)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;__name__ == &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;__main__&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;:
&lt;&#x2F;span&gt;&lt;span&gt;    asyncio.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;())
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A general execution time for the entire code could be anywhere between 5 mins — 10 mins, depending on the number of tweets fetched by your username or keyword query.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;working-with-raw-api-reponses&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#working-with-raw-api-reponses&quot; aria-label=&quot;Anchor link for: working-with-raw-api-reponses&quot;&gt;Working with raw API reponses&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;If you don’t have enough data provided by Tweet &amp;amp; User objects or want to get more insights from the data, then there is an option to use raw Twitter responses. Each method has a _raw version that returns the original data.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;py&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-py &quot;&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;asyncio
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;twscrape &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;API&lt;&#x2F;span&gt;&lt;span&gt;, gather
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;twscrape.logger &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;set_log_level
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;async def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;():
&lt;&#x2F;span&gt;&lt;span&gt;    api = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;API&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    q = &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;elon musk since:2023-01-01 until:2023-05-31&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;async for &lt;&#x2F;span&gt;&lt;span&gt;rep &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;api.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;search_raw&lt;&#x2F;span&gt;&lt;span&gt;(q, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;limit&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;5000&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# rep is httpx.Response object
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(rep.status_code, rep.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;json&lt;&#x2F;span&gt;&lt;span&gt;())
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;__name__ == &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;__main__&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;:
&lt;&#x2F;span&gt;&lt;span&gt;    asyncio.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;())
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or same from CLI:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;twscrape&lt;&#x2F;span&gt;&lt;span&gt; search &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;elon musk since:2023-01-01 until:2023-05-31&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --raw
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;list-of-available-functions&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#list-of-available-functions&quot; aria-label=&quot;Anchor link for: list-of-available-functions&quot;&gt;List of available functions&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;search&lt;&#x2F;code&gt; — just regular search by keywords&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;tweet_details&lt;&#x2F;code&gt; — information about specific tweet&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;retweeters&lt;&#x2F;code&gt; — list of users who retweet specific tweet&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;favoriters&lt;&#x2F;code&gt; — list of users who like specific tweet&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;user_by_login&lt;&#x2F;code&gt; — get user profile by login&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;user_by_id&lt;&#x2F;code&gt; — get user profile by id&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;user_tweets&lt;&#x2F;code&gt; — list of tweets of specific user (max 3200 tweets)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;user_tweets_and_replies&lt;&#x2F;code&gt; — list of tweets and replies of specific user&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;followers&lt;&#x2F;code&gt; — list of followers of specific user&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;following&lt;&#x2F;code&gt; — list of users the user is subscribed to&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;list_timeline&lt;&#x2F;code&gt; — get all tweets of list&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Found a bug or need new feature? Fill free to &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;twscrape&#x2F;issues&#x2F;new&quot;&gt;open an issues&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;More examples of use can be found on the project&#x27;s &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;twscrape&#x2F;&quot;&gt;Github page&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Better forms handling with react-use-form</title>
        <published>2023-04-04T00:00:00+00:00</published>
        <updated>2023-04-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/react-form-handling/"/>
        <id>https://vladkens.cc/react-form-handling/</id>
        
        <content type="html" xml:base="https://vladkens.cc/react-form-handling/">&lt;p&gt;React-use-form is a powerful library that simplifies form handling in React applications. Its intuitive API and robust feature set make it an excellent choice for developers.&lt;&#x2F;p&gt;
&lt;p&gt;One of its standout features is the ability to work with custom components while minimizing re-renders of the main component, which is undeniably cool. This is achieved through the use of the Controller component, although its syntax may not be the most convenient.&lt;&#x2F;p&gt;
&lt;p&gt;In this article, I’ll demonstrate how to create a generic wrapper that makes it easy to use your own components with the full power of Controller.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Imagine we have a cool input component:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;zodResolver &lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;@hookform&#x2F;resolvers&#x2F;zod&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;FC&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;useId &lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;react&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Controller&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;useForm &lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;react-hook-form&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z &lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;zod&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;SuperInputProps = {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span&gt;: string;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: string;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span&gt;: (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: string) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;void;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;error&lt;&#x2F;span&gt;&lt;span&gt;?: string;
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;SuperInput&lt;&#x2F;span&gt;&lt;span&gt;: FC&amp;lt;SuperInputProps&amp;gt; = (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;props&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;error &lt;&#x2F;span&gt;&lt;span&gt;} = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;props&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;id &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;useId&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;div&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;label &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;htmlFor&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;input &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;.target.value)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;error &lt;&#x2F;span&gt;&lt;span&gt;&amp;amp;&amp;amp; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;span&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;error&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;span&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;div&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  );
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;schema &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;object&lt;&#x2F;span&gt;&lt;span&gt;({
&lt;&#x2F;span&gt;&lt;span&gt;  firstName: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;min&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, { message: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Required&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }),
&lt;&#x2F;span&gt;&lt;span&gt;  lastName: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;z&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;min&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, { message: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Required&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }),
&lt;&#x2F;span&gt;&lt;span&gt;});
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;SuperForm&lt;&#x2F;span&gt;&lt;span&gt;: FC = () &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;control &lt;&#x2F;span&gt;&lt;span&gt;} = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;useForm&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;z.infer&amp;lt;typeof schema&amp;gt;&amp;gt;({
&lt;&#x2F;span&gt;&lt;span&gt;    resolver: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;zodResolver&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;schema&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;  });
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;form&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Controller
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;control&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;control&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;firstName&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;render&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;({ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;field&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value &lt;&#x2F;span&gt;&lt;span&gt;}, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;fieldState&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;error &lt;&#x2F;span&gt;&lt;span&gt;} }) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;          &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;SuperInput &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;First name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;error&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;error&lt;&#x2F;span&gt;&lt;span&gt;?.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        )&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;      &#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Controller
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;control&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;control&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;lastName&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;render&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;({ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;field&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value &lt;&#x2F;span&gt;&lt;span&gt;}, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;fieldState&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;error &lt;&#x2F;span&gt;&lt;span&gt;} }) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;          &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;SuperInput &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Last name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;error&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;error&lt;&#x2F;span&gt;&lt;span&gt;?.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        )&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;      &#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;form&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  );
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The part about the Controller looks verbose. If you have a lot of forms in your application, it’s tedious to write it every time. Let’s make it better!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;To do this, we first need to write some TypeScript helpers to get a list of fields in dot notation for a particular data type.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-ts &quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Primitive &lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;react-hook-form&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;NestedImpl&amp;lt;K &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;extends &lt;&#x2F;span&gt;&lt;span&gt;string | number, V, T&amp;gt; = V &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;extends &lt;&#x2F;span&gt;&lt;span&gt;T
&lt;&#x2F;span&gt;&lt;span&gt;  ? K
&lt;&#x2F;span&gt;&lt;span&gt;  : V &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;extends &lt;&#x2F;span&gt;&lt;span&gt;Primitive | Array&amp;lt;infer V&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  ? never
&lt;&#x2F;span&gt;&lt;span&gt;  : `&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;K&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}.${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;NestedByType&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;V&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;`;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;export type &lt;&#x2F;span&gt;&lt;span&gt;NestedByType&amp;lt;O, T&amp;gt; = {
&lt;&#x2F;span&gt;&lt;span&gt;  [K in keyof O]-?: K &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;extends &lt;&#x2F;span&gt;&lt;span&gt;string ? NestedImpl&amp;lt;K, O[K], T&amp;gt; : never;
&lt;&#x2F;span&gt;&lt;span&gt;}[keyof O];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; test code
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;A = { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;abc&lt;&#x2F;span&gt;&lt;span&gt;: string; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xyz&lt;&#x2F;span&gt;&lt;span&gt;: number; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;nested1&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;abc&lt;&#x2F;span&gt;&lt;span&gt;: number; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xyz&lt;&#x2F;span&gt;&lt;span&gt;: string } };
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;B = A &amp;amp; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;arr&lt;&#x2F;span&gt;&lt;span&gt;: number[] };
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;a1 = NestedByType&amp;lt;A, number&amp;gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; &amp;quot;xyz&amp;quot; | &amp;quot;nested1.abc&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;a2 = NestedByType&amp;lt;A, string&amp;gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; &amp;quot;abc&amp;quot; | &amp;quot;nested1.xyz&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;a3 = NestedByType&amp;lt;A, boolean&amp;gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; never
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;a4 = NestedByType&amp;lt;B, number[]&amp;gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; &amp;quot;arr&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;a5 = NestedByType&amp;lt;B, string&amp;gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; &amp;quot;abc&amp;quot; | &amp;quot;nested1.xyz&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we need to make a small utility to comfortably retrieve errors from the form state for specific fields.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-ts &quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getCtrlError &lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;formState&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;errors&lt;&#x2F;span&gt;&lt;span&gt;: Record&amp;lt;string, any&amp;gt; }, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: string) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tokens &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;split&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;formState&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;errors&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;token &lt;&#x2F;span&gt;&lt;span&gt;of &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tokens&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;token&lt;&#x2F;span&gt;&lt;span&gt;]) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;token&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value &lt;&#x2F;span&gt;&lt;span&gt;&amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;message &lt;&#x2F;span&gt;&lt;span&gt;? (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;message &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;string) : &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;undefined&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, we can make our Controlled wrapper for custom components.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;FC &lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;react&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Control&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Controller&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;FieldValues &lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;react-hook-form&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;makeCtrl &lt;&#x2F;span&gt;&lt;span&gt;= &amp;lt;T &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;extends &lt;&#x2F;span&gt;&lt;span&gt;Pick&amp;lt;T, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; | &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt; &amp;amp; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;error&lt;&#x2F;span&gt;&lt;span&gt;?: string }&amp;gt;(
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Component&lt;&#x2F;span&gt;&lt;span&gt;: FC&amp;lt;T&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;options&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;errorKey&lt;&#x2F;span&gt;&lt;span&gt;?: string } = {}
&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; react-hook-form has FieldPathByValue but it slow, so we use NestedByType
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;Wrapped &lt;&#x2F;span&gt;&lt;span&gt;= &amp;lt;D &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;extends &lt;&#x2F;span&gt;&lt;span&gt;FieldValues, P &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;extends &lt;&#x2F;span&gt;&lt;span&gt;NestedByType&amp;lt;D, T[&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]&amp;gt;&amp;gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;props&lt;&#x2F;span&gt;&lt;span&gt;: Omit&amp;lt;T, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; | &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; | &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;error&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt; &amp;amp; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;control&lt;&#x2F;span&gt;&lt;span&gt;: Control&amp;lt;D&amp;gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: P }
&lt;&#x2F;span&gt;&lt;span&gt;  ) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;control&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;, ...&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rest &lt;&#x2F;span&gt;&lt;span&gt;} = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;props&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;errorKey &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;options&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;errorKey &lt;&#x2F;span&gt;&lt;span&gt;? `&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}.${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;options&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;errorKey&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;` : &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;toString&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Controller
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;control&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;control&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; @ts-expect-error because of comment above
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;render&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;({ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;field&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;onChange &lt;&#x2F;span&gt;&lt;span&gt;}, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;formState &lt;&#x2F;span&gt;&lt;span&gt;}) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;error &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getCtrlError&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;formState&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;errorKey&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;toString&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;props &lt;&#x2F;span&gt;&lt;span&gt;= { ...&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rest&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;onChange&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;error &lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;unknown &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;T;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Component &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;props&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;      &#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    );
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;Wrapped&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I assume that the component for which we do wrapper has properties: value, onChange, error. These properties will be removed from the resulting component and automatically inserted into child component. But if you want to “remove” other fields, you can add them to generic type of makeCtlr function, e.g.: &lt;code&gt;makeCtrl&amp;lt;SomeType, &quot;field_to_remove_1&quot; | &quot;field_to_remove_2&quot;&amp;gt;(...)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;And now it can be used somehow like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;SuperInputCtrl &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;makeCtrl&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;SuperInput&lt;&#x2F;span&gt;&lt;span&gt;); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; create new component
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;SuperForm&lt;&#x2F;span&gt;&lt;span&gt;: FC = () &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;control &lt;&#x2F;span&gt;&lt;span&gt;} = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;useForm&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;z.infer&amp;lt;typeof schema&amp;gt;&amp;gt;({
&lt;&#x2F;span&gt;&lt;span&gt;    resolver: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;zodResolver&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;schema&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;  });
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;form&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;SuperInputCtrl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;control&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;control&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;firstName&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;First name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;SuperInputCtrl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;control&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;control&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;lastName&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Last name&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &#x2F;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;form&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  );
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now it looks much shorter, but still safe (the wrapper only allows fields that match the value type in the input). The validation error is automatically filled in. Only the input is re-rendered during data entry, not the entire form.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Better date parsing for REST API with TypeScript</title>
        <published>2022-12-15T00:00:00+00:00</published>
        <updated>2022-12-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/rest-api-date-parsing/"/>
        <id>https://vladkens.cc/rest-api-date-parsing/</id>
        
        <content type="html" xml:base="https://vladkens.cc/rest-api-date-parsing/">&lt;p&gt;A little trick in TypeScript to make it easier to work with date strings in the API. Let’s say we have a model like this on the client:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-ts &quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;User = {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;: number;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;username&lt;&#x2F;span&gt;&lt;span&gt;: string;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;createdAt&lt;&#x2F;span&gt;&lt;span&gt;: Date;
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And we transfer this data in textual protocol in JSON format, e.g. via REST API or Websockets. And we get data in a format similar to this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#2b303b;color:#c0c5ce;&quot;&gt;&lt;code&gt;&lt;span&gt;GET &#x2F;api&#x2F;users&#x2F;current
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;id&amp;quot;: &amp;quot;1234567890&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;username&amp;quot;: &amp;quot;johndoe&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;createdAt&amp;quot;: &amp;quot;2020-01-01T00:00:00.000Z&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After that, you have to write data converters from the protocol model to the data model used in the application.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-ts &quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;UserDto = {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;: number;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;username&lt;&#x2F;span&gt;&lt;span&gt;: string;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;createdAt&lt;&#x2F;span&gt;&lt;span&gt;: string;
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;decodeUser &lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dto&lt;&#x2F;span&gt;&lt;span&gt;: UserDto): User &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    id: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dto&lt;&#x2F;span&gt;&lt;span&gt;.id,
&lt;&#x2F;span&gt;&lt;span&gt;    username: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dto&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;username&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    createdAt: new Date(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dto&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;createdAt&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getCurrentUser &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;async &lt;&#x2F;span&gt;&lt;span&gt;(): Promise&amp;lt;User&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;user &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;UserDto&amp;gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;api&#x2F;users&#x2F;current&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;decodeUser&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;user&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;u &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getCurrentUser&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(typeof &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;u&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;createdAt&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;u&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;createdAt &lt;&#x2F;span&gt;&lt;span&gt;instanceof Date); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; string, false
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Basically, if the API only has a few methods, it’s not a problem to write decoders from DTO models. But usually the API is much bigger. And why should we do it if we can do not? :)&lt;&#x2F;p&gt;
&lt;p&gt;In general, if we think about JSON format, it represents all basic types except date. So if we avoid the moment with string to date conversion, we won’t need any decodes at all. Let’s fix it.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-ts &quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;parseISO &lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;date-fns&#x2F;esm&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ISODateFormat &lt;&#x2F;span&gt;&lt;span&gt;= &#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;^&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span&gt;{4}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span&gt;{2}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span&gt;{2}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span&gt;{2}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span&gt;{2}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span&gt;{2}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;(?:\.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;(?:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;[-+]\d&lt;&#x2F;span&gt;&lt;span&gt;{2}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span&gt;{2}|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;Z)&lt;&#x2F;span&gt;&lt;span&gt;?&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isIsoDateString &lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: unknown): &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value &lt;&#x2F;span&gt;&lt;span&gt;is string &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;typeof &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value &lt;&#x2F;span&gt;&lt;span&gt;=== &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ISODateFormat&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;handleDates &lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;: unknown) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isIsoDateString&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;parseISO&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;data &lt;&#x2F;span&gt;&lt;span&gt;=== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;null &lt;&#x2F;span&gt;&lt;span&gt;|| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;data &lt;&#x2F;span&gt;&lt;span&gt;=== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;undefined &lt;&#x2F;span&gt;&lt;span&gt;|| typeof &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;data &lt;&#x2F;span&gt;&lt;span&gt;!== &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;object&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;val&lt;&#x2F;span&gt;&lt;span&gt;] of &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;Object&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;entries&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;)) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; @ts-expect-error this is a hack to make the type checker happy
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isIsoDateString&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;val&lt;&#x2F;span&gt;&lt;span&gt;)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;parseISO&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;val&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;else if &lt;&#x2F;span&gt;&lt;span&gt;(typeof &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;val &lt;&#x2F;span&gt;&lt;span&gt;=== &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;object&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;handleDates&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;val&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And now we can update our http client to automatically turn date strings into a native date object.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-ts &quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;http &lt;&#x2F;span&gt;&lt;span&gt;= &amp;lt;T&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;: string, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;?: RequestInit) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;fetch&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;then&lt;&#x2F;span&gt;&lt;span&gt;((&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;handleDates&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;json&lt;&#x2F;span&gt;&lt;span&gt;()) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;Promise&amp;lt;T&amp;gt;);
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get &lt;&#x2F;span&gt;&lt;span&gt;= &amp;lt;T&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;: string) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;http&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;T&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getCurrentUser &lt;&#x2F;span&gt;&lt;span&gt;= (): Promise&amp;lt;User&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;http&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;User&amp;gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;api&#x2F;users&#x2F;current&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;u &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getCurrentUser&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ebcb8b;&quot;&gt;console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(typeof &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;u&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;createdAt&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;u&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;createdAt &lt;&#x2F;span&gt;&lt;span&gt;instanceof Date); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; object, true
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; or if you use axios you can make it event better
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;axios&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;interceptors&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;response&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;use&lt;&#x2F;span&gt;&lt;span&gt;((&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rep&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;handleDates&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rep&lt;&#x2F;span&gt;&lt;span&gt;.data);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rep&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;});
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getCurrentUser &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;async &lt;&#x2F;span&gt;&lt;span&gt;(): Promise&amp;lt;User&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rep &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;await &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;axios&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;User&amp;gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;api&#x2F;users&#x2F;current&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rep&lt;&#x2F;span&gt;&lt;span&gt;.data;
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Docker Compose templating using YAML merge feature</title>
        <published>2022-12-13T00:00:00+00:00</published>
        <updated>2022-12-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/docker-compose-merge/"/>
        <id>https://vladkens.cc/docker-compose-merge/</id>
        
        <content type="html" xml:base="https://vladkens.cc/docker-compose-merge/">&lt;p&gt;Useful trick when you have many of the same services in the &lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;p&gt;Imagine that we have some data processing application which has a master service and several different workers. All applications are written in the same language and use a common base docker container. In general this is a fairly common configuration. The &lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt; file will look something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;3.8&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;master&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;.
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ports&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;8080:8080&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;volumes&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.:&#x2F;app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;command&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;python run_master.py
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;worker-foo&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;.
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;depends_on&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;master
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;volumes&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.:&#x2F;app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;environment&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;MASTER_HOST=master:8080
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;command&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;python run_foo_worker.py
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;worker-bar&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;.
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;depends_on&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;master
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;volumes&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.:&#x2F;app&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;environment&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;MASTER_HOST=master:8080
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;command&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;python run_bar_worker.py
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It looks verbose. A lot of code duplication. Let’s fix it with YAML Anchors!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;3.8&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x-base&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;base
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;.
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;volumes&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.:&#x2F;app
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x-worker&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;worker
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;base
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;depends_on&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;master
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;environment&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;MASTER_HOST=master:8080
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;master&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;base
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ports&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;8080:8080&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;command&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;python run_master.py
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;worker-foo&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;worker
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;command&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;python run_foo_worker.py
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;worker-bar&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;worker
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;command&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;python run_bar_worker.py
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It looks much better! Such a file is easier to maintain, expand and edit in the future.&lt;&#x2F;p&gt;
&lt;p&gt;The x-field is a special property in the docker-compose.yml file. In the Docker compose documentation they are called &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.docker.com&#x2F;compose&#x2F;compose-file&#x2F;#extension&quot;&gt;extension fields&lt;&#x2F;a&gt;. You can put any valid YAML code in them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;merge-problems&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#merge-problems&quot; aria-label=&quot;Anchor link for: merge-problems&quot;&gt;Merge problems&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Note that YAML does merge at the top level and do not deep merge. So this code will not work as expected:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x-base&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;base
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;environment&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;SUPER_SECRET=42
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x-worker&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;worker
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;base
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;environment&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;MASTER_HOST=master:8080
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;worker&lt;&#x2F;code&gt; service will completely overwrite environment of base and will contain only &lt;code&gt;MASTER_HOST&lt;&#x2F;code&gt;. Unfortunately, this array combining cannot be achieved directly in the docker-compose file. Therefore, in such cases, you can use &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.docker.com&#x2F;compose&#x2F;multiple-compose-files&#x2F;extends&#x2F;&quot;&gt;extends&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solution-for-single-variable&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution-for-single-variable&quot; aria-label=&quot;Anchor link for: solution-for-single-variable&quot;&gt;Solution for single variable&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;However, if you want to make only one value common, you can put that value into a variable, and use that variable as an array element.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x-super-secret&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;super-secret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;SUPER_SECRET=42
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x-base&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;base
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;environment&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;super-secret
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x-worker&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;worker
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;base
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;environment&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;super-secret
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;MASTER_HOST=master:8080
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This can be useful for &lt;code&gt;volumes&lt;&#x2F;code&gt;, &lt;code&gt;depends_on&lt;&#x2F;code&gt; and other array-like directives.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solution-for-single-object&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution-for-single-object&quot; aria-label=&quot;Anchor link for: solution-for-single-object&quot;&gt;Solution for single object&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;As for environment, you can put the shared variables in a separate object and combine them in the same way we did with services. 🙃&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x-env&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;env
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;SUPER_SECRET&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;42
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x-base&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;base
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;environment&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;env
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x-worker&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;worker
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;base
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;environment&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;env
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;MASTER_HOST&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;master:8080
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;That’s all for now. If this information was helpful to you, don’t forget to subscribe to receive notifications of new posts.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>asdf — a good tool to manage python, node, etc runtime</title>
        <published>2022-12-10T00:00:00+00:00</published>
        <updated>2022-12-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/asdf-package-manager/"/>
        <id>https://vladkens.cc/asdf-package-manager/</id>
        
        <content type="html" xml:base="https://vladkens.cc/asdf-package-manager/">&lt;p&gt;When you develop or maintain many projects or use a microservice architecture, over time you have a zoo of different programming languages and their versions on your computer. Each service has its own dependencies. After a while it becomes hellishly difficult to work comfortably.&lt;&#x2F;p&gt;
&lt;p&gt;Initially, I controlled runtimes versions through homebrew, switching them when needed. Later I switched to nvm for NodeJS, pyenv for Python. If you add to this tools&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vladkens&#x2F;zsh-auto-nvm-use&quot;&gt; automatic version selection&lt;&#x2F;a&gt; on cd to project folder, it becomes almost comfortable. But this solution in the terminal is visually slow.&lt;&#x2F;p&gt;
&lt;p&gt;I was looking for alternatives and found an amazing tool with a strange name – &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;asdf-vm.com&#x2F;&quot;&gt;asdf&lt;&#x2F;a&gt;. This is single cli-tool for managing multiple runtimes and their versions. Each runtime is added via plugins and there are already about &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;asdf-vm&#x2F;asdf-plugins&quot;&gt;450 of them&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;asdf itself knows how to install different versions, can switch runtime when directory changed and works fast.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;installation&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#installation&quot; aria-label=&quot;Anchor link for: installation&quot;&gt;Installation&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;On MacOS you can install asdf with homebrew (for other OS follow &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;asdf-vm.com&#x2F;guide&#x2F;getting-started.html&quot;&gt;official guide&lt;&#x2F;a&gt;):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span&gt; install asdf
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After that we can set the necessary runtimes:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Install NodeJS
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; plugin-add nodejs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; install nodejs latest:16
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; install nodejs latest:14
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Install Python
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; plugin-add python
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; install python latest:3.10
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; install python latest:3.11
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Also possible to get list of available versions for inslation
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; list all nodejs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; list all python
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Or list of already installed versions
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; list nodejs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; list python
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Get current selected runtimes
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; current
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Set global runtime (will create a .tool-versions in root of user directory)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; global nodejs latest:16
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; global python latest:3.10
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Or set local runtime (will create a .tool-versions file in current directory)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; local nodejs latest:14
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; local python latest:3.10
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;version-select-on-directory-change&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#version-select-on-directory-change&quot; aria-label=&quot;Anchor link for: version-select-on-directory-change&quot;&gt;Version select on directory change&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;asdf&lt;&#x2F;code&gt; can also automatically select the correct version depending on the current directory and will do this on each &lt;code&gt;cd&lt;&#x2F;code&gt;. It does this by going up in the hierarchy until it finds version of required runtime in the &lt;code&gt;.tool-versions&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;p&gt;This allows flexible control over multiple versions of runtimes in each folder. For example you have an old project where tooling is written in python 3.8, you want to start code a new microservice in python 3.11, and globally in the system you are using version 3.9. &lt;code&gt;asdf&lt;&#x2F;code&gt; will handle it for you!&lt;&#x2F;p&gt;
&lt;p&gt;To enable this auto version select feature add next line to your shell rc-file (for more options or other shells see &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;asdf-vm.com&#x2F;guide&#x2F;getting-started.html#_3-install-asdf&quot;&gt;official guide&lt;&#x2F;a&gt;):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# For zsh (~&#x2F;.zhsrc)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;. &lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;brew --prefix&lt;&#x2F;span&gt;&lt;span&gt; asdf)&#x2F;libexec&#x2F;asdf.sh
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# For fish-shell (~&#x2F;.config&#x2F;fish&#x2F;config.fish)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;source &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;(brew --prefix asdf)&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&#x2F;libexec&#x2F;asdf.fish
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That’s all. Now just make a cd to the project folder and set the required runtime version. Now when you navigate to the project folder, asdf will automatically select python of this version. You can check selected versions with:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# for example install global python version
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; global python latest:3.11
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# go to project folder
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;some_project
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# install reqired python version (will create or update .tool-versions file)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; local python latest:3.10
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# see current active runtime versions (should be 3.10)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; current
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# check python version (should be same)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;python --version
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# go back to user folder
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# check python version again (should be 3.11)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; current
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;python --version
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Also you can commit the &lt;code&gt;.tool-versions&lt;&#x2F;code&gt; file directly into GIT. So then all team members will also know what versions of runtimes is in use for that service.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;one-more-life-story&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#one-more-life-story&quot; aria-label=&quot;Anchor link for: one-more-life-story&quot;&gt;One more life story&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Using asdf you can manage not only runtime language versions, but also cli tools such as aws-cli, terraform, kubectl.&lt;&#x2F;p&gt;
&lt;p&gt;So if you have different versions of Kubernetes clusters, even the official documentation does not recommend using more than one version of difference.&lt;&#x2F;p&gt;
&lt;p&gt;Using multiple versions via brew is not convenient (you have to switch versions manually all the time). But these cli tools can also be put in &lt;code&gt;.tool-versions&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; plugin-add kubectl https:&#x2F;&#x2F;github.com&#x2F;asdf-community&#x2F;asdf-kubectl.git
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; install kubectl latest:1.20
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; install kubectl latest:1.25
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; global kubectl latest:1.25
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;cd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;legacy_project
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;asdf&lt;&#x2F;span&gt;&lt;span&gt; local kubectl latest:1.20
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;That’s all for now. If this information was helpful to you, don’t forget to subscribe to receive notifications of new posts.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How to see env in Docker container?</title>
        <published>2022-12-06T00:00:00+00:00</published>
        <updated>2022-12-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/docker-container-env/"/>
        <id>https://vladkens.cc/docker-container-env/</id>
        
        <content type="html" xml:base="https://vladkens.cc/docker-container-env/">&lt;h2 id=&quot;tl-dr&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#tl-dr&quot; aria-label=&quot;Anchor link for: tl-dr&quot;&gt;TL;DR&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# get all
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;proc&#x2F;1&#x2F;environ | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tr &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;\0&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# get by name
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;proc&#x2F;1&#x2F;environ | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tr &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;\0&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;grep&lt;&#x2F;span&gt;&lt;span&gt; ABC
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;details&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#details&quot; aria-label=&quot;Anchor link for: details&quot;&gt;Details&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;When you develop services, sometimes you need to know what environment variables a process in a container is running with.&lt;&#x2F;p&gt;
&lt;p&gt;For example if you use kubernetes and the environment variables come from several places or if you debug a production container and want to know what environment it is running with.&lt;&#x2F;p&gt;
&lt;p&gt;Well, that&#x27;s easy. Normally your process in the docker is running under &lt;code&gt;PID=1&lt;&#x2F;code&gt;. You can check this by running the command:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; exec &amp;lt;CONTAINER_ID&amp;gt; ps aux
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# output:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PID&lt;&#x2F;span&gt;&lt;span&gt;   USER     TIME  COMMAND
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt; root      0:02 node src&#x2F;main.js
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we can see the environment variables that this process uses:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span&gt; exec &amp;lt;CONTAINER_ID&amp;gt; cat &#x2F;proc&#x2F;1&#x2F;environ | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tr &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;\0&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# output:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;NODE_VERSION&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;16.18.1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;HOSTNAME&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;544193567d05
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;YARN_VERSION&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.22.19
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;SHLVL&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;HOME&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;root
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PATH&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;usr&#x2F;local&#x2F;sbin:&#x2F;usr&#x2F;local&#x2F;bin:&#x2F;usr&#x2F;sbin:&#x2F;usr&#x2F;bin:&#x2F;sbin:&#x2F;bin
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;PWD&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This approach is also useful if you need to get environment variables of kubernetes pod:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# connect to pod
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;kubectl&lt;&#x2F;span&gt;&lt;span&gt; exec&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --stdin --tty&lt;&#x2F;span&gt;&lt;span&gt; node-app-abc123 -- &#x2F;bin&#x2F;sh
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# get process envs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;proc&#x2F;1&#x2F;environ | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;tr &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;\0&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# output: list of environment variables
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Keep Type Guards valid after refactoring in TypeScript</title>
        <published>2022-12-03T00:00:00+00:00</published>
        <updated>2022-12-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/typescript-guards/"/>
        <id>https://vladkens.cc/typescript-guards/</id>
        
        <content type="html" xml:base="https://vladkens.cc/typescript-guards/">&lt;p&gt;TypeScript is a great language for writing applications with type safety checks. Extending or refactoring code in TypeScript is much easier than in plain JavaScript.&lt;&#x2F;p&gt;
&lt;p&gt;TypeScript has a nice built-in functionality for interface narrowing — Type Guards. But they don’t always protect against errors during code extension &#x2F; refactoring, especially if you have a large project.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;problem-description&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#problem-description&quot; aria-label=&quot;Anchor link for: problem-description&quot;&gt;Problem description&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;For example, we have a tea store. We sell two kinds of tea: loose and bagged. We show all the goods in one list. Each type of product has humanised link, and in the name of the product we want to specify the number of grams or the number of tea bags in a pack.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;React &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;react&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;Tea = { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;: number; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: string; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;price&lt;&#x2F;span&gt;&lt;span&gt;: number };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;LooseTea = Tea &amp;amp; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;weight&lt;&#x2F;span&gt;&lt;span&gt;: number };
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;BaggedTea = Tea &amp;amp; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;size&lt;&#x2F;span&gt;&lt;span&gt;: number };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isLooseTea &lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: Tea): &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x &lt;&#x2F;span&gt;&lt;span&gt;is LooseTea &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;weight&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isBaggedTea &lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: Tea): &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x &lt;&#x2F;span&gt;&lt;span&gt;is BaggedTea &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;size&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getLink &lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: Tea): string &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isLooseTea&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;loose-tea&#x2F;${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.id}&lt;&#x2F;span&gt;&lt;span&gt;`;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isBaggedTea&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;&#x2F;bagged-tea&#x2F;${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.id}&lt;&#x2F;span&gt;&lt;span&gt;`;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span&gt;new Error(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Unknown tea&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getTitle &lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: Tea): string &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isLooseTea&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.name} &#x2F; ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;weight&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}g&lt;&#x2F;span&gt;&lt;span&gt;`;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isBaggedTea&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.name} &#x2F; ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.size} teabags&lt;&#x2F;span&gt;&lt;span&gt;`;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span&gt;new Error(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Unknown tea&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;TeaItems&lt;&#x2F;span&gt;&lt;span&gt;: React.FC&amp;lt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;items&lt;&#x2F;span&gt;&lt;span&gt;: Tea[] }&amp;gt; = ({ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;items &lt;&#x2F;span&gt;&lt;span&gt;}) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;items&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;((&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;li &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;key&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;.id&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;          &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;href&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getLink&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getTitle&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;li&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      ))&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ab7967;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;ul&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;  );
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Later, we got large tea bags (for the teapot) and changed our data model:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;BaggedTea = Tea &amp;amp; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;bags&lt;&#x2F;span&gt;&lt;span&gt;: number; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;weightPerBag&lt;&#x2F;span&gt;&lt;span&gt;: number };
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After that we get an error in &lt;code&gt;getTitle&lt;&#x2F;code&gt; function and fix it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; before:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getTitle &lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: Tea): string &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isLooseTea&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.name} &#x2F; ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;weight&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}g&lt;&#x2F;span&gt;&lt;span&gt;`;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Property &amp;#39;size&amp;#39; does not exist on type &amp;#39;BaggedTea&amp;#39;. ts(2339)
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isBaggedTea&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.name} &#x2F; ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.size} teabags&lt;&#x2F;span&gt;&lt;span&gt;`;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span&gt;new Error(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Unknown tea&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; after:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;getTitle &lt;&#x2F;span&gt;&lt;span&gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;: Tea): string &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isLooseTea&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.name} &#x2F; ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;weight&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}g&lt;&#x2F;span&gt;&lt;span&gt;`;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;isBaggedTea&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.name} &#x2F; ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;bags&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;} teabags ~ ${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;weightPerBag&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;`;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;throw &lt;&#x2F;span&gt;&lt;span&gt;new Error(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Unknown tea&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Everything seems to be fine and TypeScript doesn’t found any error. But in fact during the rendering process an &quot;Unknown tea&quot; error will occur, because the Type Guard in the &lt;code&gt;getLink&lt;&#x2F;code&gt; function is no longer pass in &lt;code&gt;isBaggedTea&lt;&#x2F;code&gt; guard.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;problem-solution&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#problem-solution&quot; aria-label=&quot;Anchor link for: problem-solution&quot;&gt;Problem solution&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The problem with our Type Guard is that internally we check for the presence of a field in the object. This is a JavaScript operation and it is not typed in any way.&lt;&#x2F;p&gt;
&lt;p&gt;Well, let’s handle that. I propose to use a factory function to create Type Guard functions based on the data-model fields.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;AnyObject = Record&amp;lt;string, any&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;52991061
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;RequiredKeys&amp;lt;T&amp;gt; = {
&lt;&#x2F;span&gt;&lt;span&gt;  [K in keyof T]-?: AnyObject &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;extends &lt;&#x2F;span&gt;&lt;span&gt;Pick&amp;lt;T, K&amp;gt; ? never : K;
&lt;&#x2F;span&gt;&lt;span&gt;}[keyof T];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;createShapeGuard &lt;&#x2F;span&gt;&lt;span&gt;= &amp;lt;T &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;extends &lt;&#x2F;span&gt;&lt;span&gt;AnyObject&amp;gt;(...&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;keys&lt;&#x2F;span&gt;&lt;span&gt;: RequiredKeys&amp;lt;T&amp;gt;[]) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;obj&lt;&#x2F;span&gt;&lt;span&gt;: unknown): &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;obj &lt;&#x2F;span&gt;&lt;span&gt;is T &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(typeof &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;obj &lt;&#x2F;span&gt;&lt;span&gt;!== &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;object&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; || &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;obj &lt;&#x2F;span&gt;&lt;span&gt;=== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;null&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key &lt;&#x2F;span&gt;&lt;span&gt;of &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;keys &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;string[]) {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(!(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;key &lt;&#x2F;span&gt;&lt;span&gt;in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;obj&lt;&#x2F;span&gt;&lt;span&gt;)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now let’s rewrite our Type Guards in a new way:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;isLooseTea &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;createShapeGuard&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;LooseTea&amp;gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;weight&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;isBaggedTea &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;createShapeGuard&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;BaggedTea&amp;gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;bags&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;weightPerBag&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Everything works fine now. If we change the data structure again in the future, TypeScript will check and tell us that there is now an error in our Type Guard:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;BaggedTea = Tea &amp;amp; { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;bags&lt;&#x2F;span&gt;&lt;span&gt;: number; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;bagWeight&lt;&#x2F;span&gt;&lt;span&gt;: number };
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; Argument of type &amp;#39;&amp;quot;weightPerBag&amp;quot;&amp;#39; is not assignable to parameter of type &amp;#39;RequiredKeys&amp;lt;BaggedTea&amp;gt;&amp;#39;.ts(2345)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;isBaggedTea &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8fa1b3;&quot;&gt;createShapeGuard&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;BaggedTea&amp;gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;bags&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;weightPerBag&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;That’s all for now. If this information was helpful to you, don’t forget to subscribe to receive notifications of new posts.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sync all Git branches with remote</title>
        <published>2022-12-02T00:00:00+00:00</published>
        <updated>2022-12-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/git-sync-all/"/>
        <id>https://vladkens.cc/git-sync-all/</id>
        
        <content type="html" xml:base="https://vladkens.cc/git-sync-all/">&lt;p&gt;Sometimes there is no good internet connection, but you can still work at your laptop (merge PR, etc). It’s very handy to have a local full local copy of the Git repository of a project on your computer for this purpose.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, Git itself doesn’t have out-of-the-box functionality to sync your local repository with a central server (like Github).&lt;&#x2F;p&gt;
&lt;p&gt;I searched for a solution on stackoverflow, but surprisingly there are only separate commands to do different parts of this task.&lt;&#x2F;p&gt;
&lt;p&gt;So I made this little script in bash to be able to do this synchronisation.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env bash
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Debug: Print all commands with expanded variables
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# set -x
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Get all remote refs &amp;amp; remove outdated local refs
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; fetch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --all --prune
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Create local copy of remote branch &amp;amp; load latest changes
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; rb &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; branch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --remotes &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;grep -v &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;HEAD&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;`; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;lb&lt;&#x2F;span&gt;&lt;span&gt;=$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rb&lt;&#x2F;span&gt;&lt;span&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;origin&#x2F;}
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#96b5b4;&quot;&gt;echo &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rb&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt; -&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;lb&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; branch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --track &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;lb &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;rb &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&#x2F;dev&#x2F;null
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; fetch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --update-head-ok&lt;&#x2F;span&gt;&lt;span&gt; origin $&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;lb&lt;&#x2F;span&gt;&lt;span&gt;:$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;lb
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;done
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# Remove all merged local branches
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; branch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --merged &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xargs&lt;&#x2F;span&gt;&lt;span&gt; echo | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;grep -v &lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;^*\|^main$\|^develop$|^stage$&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39; | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;xargs&lt;&#x2F;span&gt;&lt;span&gt; git branch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -d
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;Note: On line 18 you can specify a list of branches that should always remain local.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This script will also be useful if you often have to check other branches manually before merging them.&lt;&#x2F;p&gt;
&lt;p&gt;Installation &amp;amp; Run:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span&gt; https:&#x2F;&#x2F;gist.githubusercontent.com&#x2F;vladkens&#x2F;5261c703111fd1d0a870c3bf5e53c698&#x2F;raw&#x2F;698af0fdac327bcb3b7d8777a4593a4d66321bb6&#x2F;git-sync.sh &amp;gt; git-sync.sh
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;chmod&lt;&#x2F;span&gt;&lt;span&gt; +x git-sync.sh
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;.&#x2F;git-sync.sh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Docker Desktop alternative for MacOS</title>
        <published>2022-07-22T00:00:00+00:00</published>
        <updated>2022-07-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/colima-macos/"/>
        <id>https://vladkens.cc/colima-macos/</id>
        
        <content type="html" xml:base="https://vladkens.cc/colima-macos/">&lt;p&gt;Starting in February 2022, Docker Desktop became a paid service for large teams. This may be a reason to look for alternatives to Docker Desktop.&lt;&#x2F;p&gt;
&lt;p&gt;In my case one day Docker Desktop just stopped opening. The default solution of uninstalling and re-installing didn’t work. I didn’t have enough time to figure out the problem. So I looked for alternatives to running containers on macOS locally.&lt;&#x2F;p&gt;
&lt;p&gt;One of the projects I looked at is &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;abiosoft&#x2F;colima&quot;&gt;Colima&lt;&#x2F;a&gt;. I found it minimalistic to install and easy to use. Colima supports M1 &amp;amp; Intel chips, port forwarding, volume mounts, docker-compose &amp;amp; kubernetes. Basically everything you need for local development.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-to-install-colima&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-to-install-colima&quot; aria-label=&quot;Anchor link for: how-to-install-colima&quot;&gt;How to install Colima?&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Install docker &amp;amp; docker-compose client (just clients to interact with Colima containers runtime):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span&gt; install docker
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span&gt; install docker-compose
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then install Colima:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span&gt; install colima
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;usage&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#usage&quot; aria-label=&quot;Anchor link for: usage&quot;&gt;Usage&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Start Colima is easy:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;colima&lt;&#x2F;span&gt;&lt;span&gt; start
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That’s it. Now you can run your docker-compose files and everything works. To stop Colima:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;colima&lt;&#x2F;span&gt;&lt;span&gt; stop
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Colima also support different profiles, kubernetes, etc. You can check start options in &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;abiosoft&#x2F;colima#usage&quot;&gt;docs&lt;&#x2F;a&gt; or by:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;colima&lt;&#x2F;span&gt;&lt;span&gt; start&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --help
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;customising&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#customising&quot; aria-label=&quot;Anchor link for: customising&quot;&gt;Customising&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;By default Colima runs with 2 CPUs, 2GiB memory and 60GiB storage. This is not enough for me so these settings can be changed:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# stop VM before apply changes
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;colima&lt;&#x2F;span&gt;&lt;span&gt; stop
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# this will change configuration of exits VM
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;colima&lt;&#x2F;span&gt;&lt;span&gt; start&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --cpu&lt;&#x2F;span&gt;&lt;span&gt; 2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --memory&lt;&#x2F;span&gt;&lt;span&gt; 4
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# or by changing config file
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;colima&lt;&#x2F;span&gt;&lt;span&gt; start&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; --edit
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;possible-problems&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#possible-problems&quot; aria-label=&quot;Anchor link for: possible-problems&quot;&gt;Possible problems&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;If you are using utilities such as &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;moncho&#x2F;dry&quot;&gt;dry&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;wagoodman&#x2F;dive&quot;&gt;dive&lt;&#x2F;a&gt;, they may not start with the error like “docker.sock not found”. This is easy to fix:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; ln&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt; -sf ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;.colima&#x2F;docker.sock &#x2F;var&#x2F;run&#x2F;docker.sock
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;That’s all for now. I hope that article was useful for you. If yes, don’t forget to follow me to get new updates.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How to reduce NodeJS Docker Image Size?</title>
        <published>2022-01-16T00:00:00+00:00</published>
        <updated>2022-01-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              vladkens
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://vladkens.cc/small-nodejs-docker-image/"/>
        <id>https://vladkens.cc/small-nodejs-docker-image/</id>
        
        <content type="html" xml:base="https://vladkens.cc/small-nodejs-docker-image/">&lt;p&gt;Hi. Today I want to talk about how to reduce the size of the Docker Image with NodeJS inside.&lt;&#x2F;p&gt;
&lt;p&gt;In my company project we use NodeJS as a backend of one of the services. I noticed that there is a big delay between when the project is built in CI and when the new version of the service actually starts working.&lt;&#x2F;p&gt;
&lt;p&gt;I started researching this topic and noticed that the NodeJS Docker Image size takes up 1.3Gb of space. So on each deploy these data first uploaded to registry and then downloaded back to run in Kubernetes cluster.&lt;&#x2F;p&gt;
&lt;p&gt;To check the size of your Docker need to run few commands:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span&gt;&amp;gt; docker &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;build -t&lt;&#x2F;span&gt;&lt;span&gt; app .
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; docker &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;images &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;grep&lt;&#x2F;span&gt;&lt;span&gt; app
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;     latest    62dec8181ae0   30 seconds ago   1.28GB
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Well, let’s fix that problem.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;smaller-docker-base-image&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#smaller-docker-base-image&quot; aria-label=&quot;Anchor link for: smaller-docker-base-image&quot;&gt;Smaller Docker Base Image&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The most basic and simple solution would be to change the basic Docker Image to the alpine version. To do this, change in the first line of the Dockerfile &lt;code&gt;FROM node:16&lt;&#x2F;code&gt; to &lt;code&gt;FROM node:16-alpine&lt;&#x2F;code&gt;. This was already in my Dockerfile, so this optimization won’t help me. The original Docker file looks like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;FROM node:16-alpine
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;WORKDIR &#x2F;app
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;COPY . .
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;RUN yarn install
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;RUN yarn app:build
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;EXPOSE 3000
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CMD node dist&#x2F;app.js
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;multi-stage-builds&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#multi-stage-builds&quot; aria-label=&quot;Anchor link for: multi-stage-builds&quot;&gt;Multi-Stage Builds&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The process of creating a Docker container can be divided into several steps, where different parts of the application are prepared individually. And then the necessary files from the intermediate stages can be copied into the final image.&lt;&#x2F;p&gt;
&lt;p&gt;This makes sense, because during the build a lot of temporary files are created, there are dev dependencies in package.json and other things that are not really needed for the final application to work.&lt;&#x2F;p&gt;
&lt;p&gt;I divided the build process of container into three steps. The first step builds the application (compiling the TypeScript, validation schemes, etc.). The second stage installs only those dependencies that are needed for the production of the application. Finally, the third stage copies the compiled application from the first stage and the dependencies from the second stage and runs the application.&lt;&#x2F;p&gt;
&lt;p&gt;This approach requires a little more time to build the container, but it also reduces its size considerably. For example, the TypeScript dependency alone takes up over 80 mb of space. The final Dockerfile looks like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;FROM node:16-alpine as dist
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;WORKDIR &#x2F;app
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;COPY . .
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;RUN yarn install
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;RUN yarn app:build
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;FROM node:16-alpine as deps
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;WORKDIR &#x2F;app
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;COPY package.json yarn.lock .&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;RUN yarn install --production --frozen-lockfile
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;FROM node:16-alpine
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;WORKDIR &#x2F;app
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;COPY --from=deps &#x2F;app&#x2F;node_modules .&#x2F;node_modules
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;COPY --from=dist &#x2F;app&#x2F;package.json &#x2F;app&#x2F;.env .&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;COPY --from=dist &#x2F;app&#x2F;dist&#x2F;src .&#x2F;src
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;EXPOSE 3090
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;# CMD du -sh .&#x2F;node_modules&#x2F;* | sort -nr | grep &amp;#39;\dM.*&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;CMD node src&#x2F;app.js
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In line 19 I comment a sh command to print size of depencencies in &lt;code&gt;node_modules&lt;&#x2F;code&gt;. So you can check what dependencies remained in the final build and possibly remove some of them, or replace them with the optimal version. For example, if you use AWS S3 in your application, you can use a dependency only for S3 and not for all AWS services.&lt;&#x2F;p&gt;
&lt;p&gt;Final size of the Docker Image is 322Mb, which 4x times smaller than original image.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span&gt;&amp;gt; docker &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;images &lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;grep&lt;&#x2F;span&gt;&lt;span&gt; app
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;     latest    b6f283f00bb2   12 seconds ago   322MB
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot;&gt;Conclusion&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Using simple things you can reduce the size of the image of your application and speed up the time between building and running the application in the production.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;That’s all for now. I hope that article was useful for you. If yes, don’t forget to follow me to get new updates.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
