<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>AlexandreHTRB&#39;s blog</title>
  <subtitle>Content about programming and some other topics.</subtitle>
  <link href="https://alexandrehtrb.github.io/atom.xml" rel="self" />
  <link href="https://alexandrehtrb.github.io/" />
  <updated>2026-06-23T00:00:00Z</updated>
  <id>https://alexandrehtrb.github.io/</id>
  <author>
    <name>Alexandre H. T. R. Bonfitto</name>
  </author>
  <entry>
    <title>Periodic table of computing</title>
    <link href="https://alexandrehtrb.github.io/posts/2026/06/periodic-table-of-computing/" />
    <updated>2026-06-23T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2026/06/periodic-table-of-computing/</id>
    <content type="html">&lt;p&gt;A few days ago, I was thinking about the different file extensions of programming languages and realized that they look like symbols of chemical elements. Then I thought: &quot;we could make a periodic table of computing&quot;.&lt;/p&gt;&lt;p&gt;The best HTML periodic table I found on the Internet was the one from &lt;a href=http://adrianroselli.com/2019/05/periodic-table-of-the-elements.html&gt;Adrian Roselli&lt;/a&gt;. It&#39;s responsive, works on vertical and horizontal, covers all the accessibility needs, supports dark mode, works offline and you can even print it!&lt;/p&gt;&lt;p&gt;I tried to make a table including everything I consider important on computing as a whole, in a broader sense. There was no space left for things like architecture and design patterns. Maybe that would be better in a periodic table of software, instead of computing.&lt;/p&gt;&lt;p&gt;Click &lt;a href=https://alexandrehtrb.github.io/periodic_table_of_computing.html&gt;here&lt;/a&gt; to view the table.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Making a holiday calendar with functional programming</title>
    <link href="https://alexandrehtrb.github.io/posts/2026/01/making-a-holiday-calendar-with-functional-programming/" />
    <updated>2026-01-06T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2026/01/making-a-holiday-calendar-with-functional-programming/</id>
    <content type="html">&lt;p&gt;One of my personal projects is the website &lt;a href=https://feriadosdobrasil.github.io&gt;Feriados do Brasil&lt;/a&gt;, which is a calendar that displays national, state and municipal holidays of many cities in Brazil. While I was developing this project, I found an interesting use case to apply functional programming and wanted to share it in this article, showing how FP can provide unique and elegant solutions.&lt;/p&gt;&lt;h2 id=fixed-and-moveable-holidays tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2026/01/making-a-holiday-calendar-with-functional-programming/#fixed-and-moveable-holidays class=header-anchor&gt;&lt;span&gt;Fixed and moveable holidays&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;There are two kinds of holidays: fixed feasts, whose dates always happen in the same day of the same month, and moveable feasts, whose date varies every year. The most common moveable feasts in Brazil are Holy Friday, Carnival and &lt;em&gt;Corpus Christi&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Although less common, there are many other moveable holidays, each with its own determinative rule. The table below shows some of them.&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Moveable holiday&lt;/th&gt;&lt;th style=text-align:center&gt;Date&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Holy Friday&lt;/td&gt;&lt;td style=text-align:center&gt;calculated via mathematical formula&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Carnival Tuesday*&lt;/td&gt;&lt;td style=text-align:center&gt;47 days before Easter&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;&lt;em&gt;Corpus Christi&lt;/em&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;60 days after Easter&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Pentecost&lt;/td&gt;&lt;td style=text-align:center&gt;50 days after Easter&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Sacred Heart of Jesus&lt;/td&gt;&lt;td style=text-align:center&gt;8 days after &lt;em&gt;Corpus Christi&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Commerce Day on&lt;br&gt;Rio de Janeiro&lt;/td&gt;&lt;td style=text-align:center&gt;Third Monday of October&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;State holidays&lt;br&gt;on Acre**&lt;/td&gt;&lt;td style=text-align:center&gt;If within Tuesday and Thursday,&lt;br&gt;they get transferred to Friday&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;State holidays on&lt;br&gt;Santa Catarina&lt;/td&gt;&lt;td style=text-align:center&gt;If on work day,&lt;br&gt;they get transferred to Sunday&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;em class=&quot;italic text-sm&quot;&gt;* Carnival is not an official holiday, although celebrated in almost the entire country.&lt;br&gt;** Except for the State Anniversary, on June 15th.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;The question is: how can we store holidays in a database, considering that some are fixed and some are moveable? Furthermore, each moveable feast has its own rule?&lt;/p&gt;&lt;h2 id=solution-with-functional-programming tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2026/01/making-a-holiday-calendar-with-functional-programming/#solution-with-functional-programming class=header-anchor&gt;&lt;span&gt;Solution with functional programming&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;In this project, the listing and calculation of holidays are done entirely on the frontend, in JavaScript. Basically, a city&#39;s holidays are the union between national, state and municipal holidays. In the code, each set of holidays is represented by an array of functions.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;const&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt; nationalHolidays&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  ff&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt;JANUARY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;New Year&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  mf&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;calculateCarnivalTuesday&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Carnival&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  mf&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;calculateHolyFriday&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Holy Friday&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  ff&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt;APRIL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;21&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Tiradentes&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  ff&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt;MAY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Worker&#39;s Day&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  ff&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt;SEPTEMBER&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;7&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Independency of Brazil&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  ff&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt;OCTOBER&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;12&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Our Lady the Appeared&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  ff&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt;OCTOBER&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;28&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Public Worker Day&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  ff&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt;NOVEMBER&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;All Souls&#39; Day&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  ff&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt;NOVEMBER&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;15&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Proclamation of the Republic&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  ff&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt;NOVEMBER&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;20&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Black Consciousness Day&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  ff&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt;DECEMBER&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;25&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Christmas&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;ff&lt;/code&gt; and &lt;code&gt;mf&lt;/code&gt; respectively represent &lt;em&gt;fixed feast&lt;/em&gt; and &lt;em&gt;moveable feast&lt;/em&gt;. These functions receive either the day and month or a function to calculate the date, and also a description. They return another function, which receives a numerical year and returns a holiday object, with the description and the exact date (JavaScript &lt;code&gt;Date&lt;/code&gt;).&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// fixed feast&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;function&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; ff&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;month&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;day&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;desc&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;  return&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; function&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;year&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;    return&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; { &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;date:&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; new&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; Date&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;year&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;month&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;day&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;description:&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; desc&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// moveable feast&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;function&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; mf&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;funcCalcDate&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;desc&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;  return&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; function&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;year&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;    return&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; { &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;date:&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; funcCalcDate&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;year&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;description:&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; desc&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we use two functional programming concepts: higher-order functions and currying.&lt;/p&gt;&lt;p&gt;Higher-order functions are functions that receive other functions as input parameters or that return functions as outputs (or even both things at the same time). &lt;code&gt;mf()&lt;/code&gt; receives &lt;code&gt;funcCalcDate&lt;/code&gt; as an argument, which will receive a numerical year and return a Date object. Both &lt;code&gt;mf()&lt;/code&gt; and &lt;code&gt;ff()&lt;/code&gt; return functions.&lt;/p&gt;&lt;p&gt;Currying is a strategy of nesting functions inside other functions. In our case, &lt;code&gt;ff&lt;/code&gt; and &lt;code&gt;mf&lt;/code&gt; nest the internal &lt;code&gt;function (year) {...}&lt;/code&gt;. Check out this other &lt;a href=https://alexandrehtrb.github.io/posts/2025/09/what-is-currying&gt;article&lt;/a&gt; to learn more about currying.&lt;/p&gt;&lt;p&gt;To obtain the holidays of a year, all we need is to iterate each function in the array, passing the year as argument:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; year&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 2026&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; holidays&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; nationalHolidays&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;map&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;((&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;func&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;=&gt;&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; func&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;year&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// returns:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  { &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;date:&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; new&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; Date&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2026&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;description:&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;New Year&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  { &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;date:&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; new&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; Date&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2026&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;17&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;description:&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;Carnival&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  { &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;date:&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; new&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; Date&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2026&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;description:&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;Holy Friday&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The website&#39;s code is public and is available on &lt;a href=https://github.com/alexandrehtrb/FeriadosDoBrasil/blob/master/feriados_calculo.js&gt;GitHub&lt;/a&gt;. Comments and variables&#39; names are written in Portuguese.&lt;/p&gt;&lt;h2 id=interesting-reads tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2026/01/making-a-holiday-calendar-with-functional-programming/#interesting-reads class=header-anchor&gt;&lt;span&gt;Interesting reads&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://en.wikipedia.org/wiki/Public_holidays_in_Brazil&gt;Wikipedia - Public holidays in Brazil&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://www.tondering.dk/claus/cal/easter.php&gt;The Calendar FAQ - Easter&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Excel as a frontend</title>
    <link href="https://alexandrehtrb.github.io/posts/2025/09/excel-as-a-frontend/" />
    <updated>2025-09-29T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2025/09/excel-as-a-frontend/</id>
    <content type="html">&lt;p&gt;&lt;picture class=my-4&gt;&lt;source alt=&quot;Mr. Burns from The Simpsons saying Excellent&quot; srcset=https://alexandrehtrb.github.io/assets/img/posts/2025_09_mr_burns_excellent.avif type=image/avif&gt;&lt;img alt=&quot;Mr. Burns from The Simpsons saying Excellent&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2025_09_mr_burns_excellent.jpg&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;Corporate and personal finances. Governmental and management reports. Account statements. Inventory. Projections. Simulations. Lists of people. 90% of the global GDP. What do all those things have in common?&lt;/p&gt;&lt;p&gt;They go through Excel.&lt;/p&gt;&lt;p&gt;On the projects I have worked on, one of the most common features requested by clients is exporting data to Excel, especially for back-office operations, so analysts can more easily find information, make reports and calculate sums. Not just back-office — field agents, support and sales people also use it.&lt;/p&gt;&lt;p&gt;Some real-life examples:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Internal reports of transactions per individual;&lt;/li&gt;&lt;li&gt;Reports of sales grouped by business partners;&lt;/li&gt;&lt;li&gt;A salesman that needs to see which offers are available for a customer;&lt;/li&gt;&lt;li&gt;An economist that needs the inflation rates of previous months;&lt;/li&gt;&lt;li&gt;An HR analyst checking employees&#39; worked hours;&lt;/li&gt;&lt;li&gt;An investment manager analysing the historical valuation of a product.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Excel is a great tool for visualizing data and is very intuitive, easily used by anyone.&lt;/p&gt;&lt;p&gt;Considering that many times it is the final data format, here is the question: instead of having a web app, backend and frontend, hosting, servers, etc., can&#39;t we just do everything on Excel? Wouldn&#39;t it be easier? In this article, let&#39;s explore this idea.&lt;/p&gt;&lt;h2 id=connecting-to-external-data-sources tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/09/excel-as-a-frontend/#connecting-to-external-data-sources class=header-anchor&gt;&lt;span&gt;Connecting to external data sources&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Excel can connect to external sources and download data from them. Many integrations are available, such as:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;XMLs from the internet&lt;/li&gt;&lt;li&gt;XML, CSV, TXT and XLSX files&lt;/li&gt;&lt;li&gt;Flat files&lt;/li&gt;&lt;li&gt;Databases, like SQL Server, PostgreSQL, MySQL&lt;/li&gt;&lt;li&gt;Azure Blob Storage&lt;/li&gt;&lt;li&gt;HTTP endpoints&lt;/li&gt;&lt;li&gt;And others.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For example, let&#39;s create a local XML file with the content below:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;yearly_inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2014&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;1.6%&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2015&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;0.1%&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2016&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;1.3%&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2017&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2.1%&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2018&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2.4%&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2019&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;1.8%&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2020&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;1.2%&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2021&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;4.7%&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2022&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;8.0%&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2023&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;4.1%&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2024&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;year&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;2.9%&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;rate&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;yearly_inflation&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On Excel, on the &lt;strong&gt;Data&lt;/strong&gt; tab, let&#39;s click on &lt;strong&gt;New Query&lt;/strong&gt; &gt; &lt;strong&gt;From File&lt;/strong&gt; &gt; &lt;strong&gt;From XML&lt;/strong&gt;, and then select our file.&lt;/p&gt;&lt;img alt=&quot;Excel - Import external XML file data source&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2025_09_excel_import_xml_file_en.png class=my-4&gt;&lt;p&gt;After importing, the result will be:&lt;/p&gt;&lt;img alt=&quot;Excel - Result after importing XML file&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2025_09_excel_import_xml_file_result_en.png class=my-4&gt;&lt;p&gt;Whenever you wish to pull data, you can go on &lt;strong&gt;Data&lt;/strong&gt; &gt; &lt;strong&gt;Refresh All&lt;/strong&gt;, and the table will be updated with the latest remote data.&lt;/p&gt;&lt;img alt=&quot;Excel - Refresh remote connection&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2025_09_excel_refresh_data_source_en.png class=my-4&gt;&lt;h2 id=advantages tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/09/excel-as-a-frontend/#advantages class=header-anchor&gt;&lt;span&gt;Advantages&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Having Excel pull remote data has many advantages.&lt;/p&gt;&lt;p&gt;One of them is that we don&#39;t need to spend effort, time or infrastructure building a website to make that information available; all we need is the data source and a spreadsheet.&lt;/p&gt;&lt;p&gt;Even information security is solved for us:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;If the data source is a remote file, we just need to control access permission on it.&lt;/li&gt;&lt;li&gt;If the data source is a database or HTTP endpoint, we can provide a personalized credential with permissions only for specific queries.&lt;/li&gt;&lt;li&gt;Windows Authentication is an option for the cases above.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Another advantage is that once downloaded, the data is available for usage even if there is no internet connection.&lt;/p&gt;&lt;p&gt;Last, having individual spreadsheets gives users a great degree of freedom, because they can customize them however they want.&lt;/p&gt;&lt;h2 id=write-operations tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/09/excel-as-a-frontend/#write-operations class=header-anchor&gt;&lt;span&gt;Write operations&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Can we use Excel to insert, delete and modify remote data? The answer is yes. UserForms and macros are the way to achieve that.&lt;/p&gt;&lt;p&gt;UserForms are custom dialogs for user data input. Macros on the other hand are the code behind, responsible for data validations and connecting to the database and server.&lt;/p&gt;&lt;img alt=&quot;Excel - UserForm&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2025_09_excel_userform.png class=my-4&gt;&lt;p&gt;&lt;em class=&quot;italic text-sm&quot;&gt;Userform example on Excel.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Keep in mind that whenever a change is required on those write integrations, users will need to download updated versions of the spreadsheet.&lt;/p&gt;&lt;p&gt;I recommend the following userform tutorials: one from &lt;a href=https://www.excel-easy.com/vba/userform.html&gt;Excel Easy&lt;/a&gt; and another from &lt;a href=https://www.wiseowl.co.uk/vba-macros/guides/user-forms/vba-userform/ &gt;Wise Owl Training&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=final-thoughts tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/09/excel-as-a-frontend/#final-thoughts class=header-anchor&gt;&lt;span&gt;Final thoughts&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;For internal services within a business, or those that heavily rely on mathematics and reports, Excel can definitely be a good frontend solution.&lt;/p&gt;&lt;p&gt;When I discovered that Excel can connect to external data sources, I thought &quot;how come I didn&#39;t know about this earlier?&quot;. It makes a lot of sense. Since it&#39;s a software not widely used by IT professionals, interesting features like this may go unnoticed by us, even though they could help us a lot.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>What is currying?</title>
    <link href="https://alexandrehtrb.github.io/posts/2025/09/what-is-currying/" />
    <updated>2025-09-04T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2025/09/what-is-currying/</id>
    <content type="html">&lt;p&gt;Currying is a strategy for sharing logic in programming. With it, functions are nested inside others, each one responsible for a parameter of the whole logic.&lt;/p&gt;&lt;p&gt;JavaScript example:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// curried function&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;function&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; multiplyAndSum&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;a&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;  return&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; function&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;b&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;    return&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; function&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;      return&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; a&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;*&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; +&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; b&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;const&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt; f&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; multiplyAndSum&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// f(x) = 2x + 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;console&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;log&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;f&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)); &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// 9&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;const&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt; g&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; multiplyAndSum&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// g(x) = 3x + b&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// b unspecified&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;console&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;log&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;g&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)); &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// 5, b = 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With currying, derived functions can pre-fill arguments of a parent function and inherit the declaration of remaining parameters.&lt;/p&gt;&lt;p&gt;Curried functions can be imagined as &lt;a href=https://en.wikipedia.org/wiki/Matryoshka_doll&gt;&lt;em&gt;matryoshka&lt;/em&gt;&lt;/a&gt; Russian dolls: one inside another, inside another.&lt;/p&gt;&lt;img alt=&quot;Matryoshka Russian dolls&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2025_09_matryoshka.jpg&gt;&lt;p&gt;&lt;em class=&quot;italic text-sm&quot;&gt;Image source: &lt;a href=https://pt.aliexpress.com/item/1005010505814497.html&gt;AliExpress&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;This style comes from functional programming and is very useful for mathematics.&lt;/p&gt;&lt;p&gt;Another example, in F#:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; volumePyramid&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;baseAreaFormula&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;w&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;l&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;h&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  h &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;baseAreaFormula&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;w&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;l&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;))/&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; areaRectangle&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;w&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;l&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; w &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; l&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; areaTriangle&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;w&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;l&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;w &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; l&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)/&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; areaCircle&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;_&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;r&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Math.PI &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; r&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;**&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; volumeRectangularBasePyramid&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  volumePyramid&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;areaRectangle&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; volumeTriangularBasePyramid&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  volumePyramid&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;areaTriangle&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; volumeCone&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  volumePyramid&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;areaCircle&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;0&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// usage&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; v1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; volumeRectangularBasePyramid&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;7.0&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4.0&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;11.0&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; vc&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; volumeCone&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;9.0&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;12.0&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt; // radius 9, height 12&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The less a parameter varies across functions, the further to the left it should be in a curried declaration.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Containers should be an operating system responsibility</title>
    <link href="https://alexandrehtrb.github.io/posts/2025/06/containers-should-be-an-operating-system-responsibility/" />
    <updated>2025-06-10T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2025/06/containers-should-be-an-operating-system-responsibility/</id>
    <content type="html">&lt;p&gt;Not before 2018, gradually, my colleagues at work started talking about Docker, a technology for setting up environments for applications on servers. In less than two years, Docker had become the standard and new backend apps included Dockerfiles and YAMLs for Kubernetes.&lt;/p&gt;&lt;p&gt;Even though I understood what containers were for, part of me said that they were an overweight solution, and the problems solved by them should actually be solved by operating systems. My opinion still stands.&lt;/p&gt;&lt;p&gt;In this article, let&#39;s cover some alternatives to containers and propose a solution that could be implemented by operating systems.&lt;/p&gt;&lt;h2 id=beginning-from-the-end tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/06/containers-should-be-an-operating-system-responsibility/#beginning-from-the-end class=header-anchor&gt;&lt;span&gt;Beginning from the end&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;After all, why do we use containers? The majority of the answers will be: &quot;To run my app in the cloud&quot;.&lt;/p&gt;&lt;p&gt;Docker solved two problems: environment setup and safe execution.&lt;/p&gt;&lt;p&gt;Docker images include everything needed to run the app, which usually is the app runtime, its dependencies and the user space of an operating system. This can be sensitive, especially for Linux, because the dependency tree may be fragile and break when an inner dependency is updated. Having a rigid and reproducible dependency tree ensures environment stability.&lt;/p&gt;&lt;p&gt;Safe execution results from the container being a process with an isolated file system and network, reducing the risk of attacks and infections on the host machine.&lt;/p&gt;&lt;h3&gt;Environment setup, without containers&lt;/h3&gt;&lt;p&gt;There are many ways to setup an environment without resorting to containers.&lt;/p&gt;&lt;p&gt;One is actually installing the required dependencies on the host machine.&lt;/p&gt;&lt;p&gt;Another is self-contained deployment, where the compilation includes the runtime alongside or inside the program. Thus, the target machine does not require the runtime to be installed to run the app.&lt;/p&gt;&lt;p&gt;Some languages offer ahead-of-time compilation (AOT), which compiles into native machine code. This allows program execution without runtime, and lowers the number of required external dependencies. As a positive side effect, AOT compilation also produces apps with better performance and reduced memory usage.&lt;/p&gt;&lt;p&gt;An operating system&#39;s Docker image corresponds to its &lt;em&gt;user space&lt;/em&gt;, which is the operating system minus its kernel. This includes essential programs, libraries, services and some other files.&lt;/p&gt;&lt;p&gt;Loading an entire operating system&#39;s user space for each container instance wastes memory and disk space. Ubuntu&#39;s Docker image, for instance, uses 188MB, which is a lot. There are ultra-light images that leave only what is strictly necessary; for example, Alpine Linux image uses only 5MB. Nevertheless, it&#39;s still an additional weight.&lt;/p&gt;&lt;p&gt;The solutions above show how to mitigate the risk of a fragile dependency tree.&lt;/p&gt;&lt;h3&gt;Safe execution, without containers&lt;/h3&gt;&lt;p&gt;This is a bit more complicated. Here, we want to limit the access to the host machine&#39;s file system and network.&lt;/p&gt;&lt;p&gt;On most operating systems, file system access control is done at user-level. In order to restrict a program&#39;s access to specific files and directories, we need to create a user (or user group) with those rules and ensure the program always runs under that user.&lt;/p&gt;&lt;p&gt;Network restriction, on the other hand, is done via firewall, with user and program-scoped rules.&lt;/p&gt;&lt;h2 id=proposal%3A-execution-manifests tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/06/containers-should-be-an-operating-system-responsibility/#proposal%3A-execution-manifests class=header-anchor&gt;&lt;span&gt;Proposal: Execution manifests&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;A suggestion to be implemented by operating systems would be execution manifests, that clearly define how a program is executed and its system permissions.&lt;/p&gt;&lt;p&gt;The execution manifest could also define which devices and peripherals a program can interact with. This would make it useful for desktop applications too.&lt;/p&gt;&lt;p&gt;The manifest file could be signed with a public-private key pair for authentication. A hash would verify that the executable file corresponds to the one expected in the manifest.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;manifestVersion&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;v1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;author&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;myCompany&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;myApp&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;./myapp&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;hash&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&amp;lt;executable_file_hash&gt;&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt; # optional&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;allowedDirectories&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;appDir&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    path&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;./**/&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt; # all subdirectories&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    permission&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;read&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;sharedFolder&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    path&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&#92;&#92;EnvGeoServer&#92;Repository&#92;Tools&#92;admin&#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    permission&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;readWrite&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;allowedNetwork&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;localhost&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    direction&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;inbound&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    ip&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;127.0.0.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    protocol&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    port&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;8080&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;allowedDevices&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  - &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;mouse&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  - &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;keyboard&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  - &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;audioOut&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  - &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;display&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=sources-and-interesting-reads tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/06/containers-should-be-an-operating-system-responsibility/#sources-and-interesting-reads class=header-anchor&gt;&lt;span&gt;Sources and interesting reads&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://iximiuz.com/en/posts/you-dont-need-an-image-to-run-a-container/ &gt;Ivan Velichko - You Don&#39;t Need an Image To Run a Container&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://stackoverflow.com/questions/32756988/what-is-meant-by-shared-kernel-in-docker&gt;Stack Overflow - What is meant by shared kernel in Docker?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/windows/win32/secauthz/appcontainer-isolation&gt;AppContainer isolation - Win32 apps | Microsoft Learn&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://superuser.com/questions/1238613/restrict-access-to-files-by-list-of-programs&gt;SuperUser - Restrict access to files by list of programs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://stackoverflow.com/questions/11345374/prevent-accessing-files-outside-of-given-working-directory&gt;Stack Overflow - Prevent accessing files outside of given working directory&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://stuff.mit.edu/afs/sipb/project/android/docs/guide/topics/manifest/manifest-intro.html&gt;The AndroidManifest.xml File | Android Developers&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://en.wikipedia.org/wiki/Ahead-of-time_compilation&gt;Wikipedia - Ahead-of-time compilation&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Structured logging in .NET with NativeAOT</title>
    <link href="https://alexandrehtrb.github.io/posts/2025/04/structured-logging-in-dotnet-with-nativeaot/" />
    <updated>2025-04-15T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2025/04/structured-logging-in-dotnet-with-nativeaot/</id>
    <content type="html">&lt;p&gt;NativeAOT and trimming are two new .NET compiler options that came up over the last years, resulting in applications with smaller sizes, faster execution and lower memory usage. In a short explanation, NativeAOT compiles to native machine code and trimming removes unused code.&lt;/p&gt;&lt;p&gt;To apply these options, all code paths must be statically determinable, i.e., &lt;strong&gt;the program cannot use reflection&lt;/strong&gt;, under the risk of having removed important parts of code and having undesirable behaviours during execution.&lt;/p&gt;&lt;p&gt;Currently, most logging libraries do use reflection, mainly to support structured logging. In this article, we will see how to make a custom structured logger, compatible with NativeAOT and trimming.&lt;/p&gt;&lt;h2 id=structured-logging tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/04/structured-logging-in-dotnet-with-nativeaot/#structured-logging class=header-anchor&gt;&lt;span&gt;Structured logging&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;In a structured log, messages are formatted in a key-value structure, like JSON or XML. This format allows easier processing by databases and logging engines.&lt;/p&gt;&lt;p&gt;Consider the code below:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; city&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;Bento Gonçalves / RS&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;WeatherForecast&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; forecast&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; new&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    minTemp&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;16&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    maxTemp&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;21&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    rainMm&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;32.5&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    windKph&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;6&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;using&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;logger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;BeginScope&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;{@Forecast}&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;forecast&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    logger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;LogInformation&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;        &quot;Weather forecast for {City} on {Date}&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;        city&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;DateTime&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Today&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;JSON structured log:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;Timestamp&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;2025-04-12T20:25:57.8532799Z&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;Level&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Information&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;Template&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Weather forecast for {City} on {Date}&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;City&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Bento Gonçalves / RS&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;Date&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;2025-04-13&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;@Forecast&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;    &quot;MinTemperatureInC&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;16&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;    &quot;MaxTemperatureInC&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;21&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;    &quot;RainInMm&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;32.5&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;    &quot;WindInKph&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;6&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When a parameter between braces is prefixed with an &#39;@&#39; sign (&lt;em&gt;arroba&lt;/em&gt;), it is treated as a complex object and its internal properties are read as key-value pairs. Without this sign, the parameter is treated as a simple value, like a number, a Guid or a string.&lt;/p&gt;&lt;p&gt;Scopes are complementary information, that may be relevant.&lt;/p&gt;&lt;h2 id=ilogger-interface-in-.net tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/04/structured-logging-in-dotnet-with-nativeaot/#ilogger-interface-in-.net class=header-anchor&gt;&lt;span&gt;&lt;code&gt;ILogger&lt;/code&gt; interface in .NET&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Modern .NET makes extensive usage of the &lt;code&gt;Microsoft.Extensions.Logging.ILogger&lt;/code&gt; interface (&lt;a href=https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/ILogger.cs&gt;source code&lt;/a&gt;):&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;namespace&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Extensions&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Logging&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; interface&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; ILogger&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    void&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; Log&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;TState&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt;(&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;LogLevel&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; logLevel&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;EventId&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; eventId&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;TState&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; state&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Exception&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;? &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;exception&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Func&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;TState&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Exception&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;?, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt; &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;formatter&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    bool&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; IsEnabled&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;LogLevel&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; logLevel&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;    IDisposable&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;? &lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;BeginScope&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;TState&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt;(&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;TState&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; state&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;where&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; TState&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; : &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;notnull&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Although not explicit in the interface, &lt;code&gt;TState&lt;/code&gt; virtually always is a type inheriting from &lt;code&gt;IReadOnlyList&amp;lt;KeyValuePair&amp;lt;string, object?&gt;&gt;&lt;/code&gt;, this is verifiable by looking at .NET runtime source code: &lt;a href=https://github.com/dotnet/runtime/blob/e220a94d842524b408c35b381fc326c4159005f0/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/LoggerExtensions.cs#L486&gt;LoggerExtensions&lt;/a&gt; and &lt;a href=https://github.com/dotnet/runtime/blob/e220a94d842524b408c35b381fc326c4159005f0/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/FormattedLogValues.cs#L16&gt;FormattedLogValues&lt;/a&gt; classes.&lt;/p&gt;&lt;p&gt;&lt;code&gt;TState&lt;/code&gt; contains key-value pairs, including the message template and parameters&#39; values. This is valid for both &lt;code&gt;Log&lt;/code&gt; and &lt;code&gt;BeginScope&lt;/code&gt; methods.&lt;/p&gt;&lt;h2 id=reflectionless-logger tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/04/structured-logging-in-dotnet-with-nativeaot/#reflectionless-logger class=header-anchor&gt;&lt;span&gt;Reflectionless logger&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The question here is how to format a log message in a generic way and without resorting to reflection.&lt;/p&gt;&lt;p&gt;As a solution, we will make a JSON logger with the help of source generators. On the &lt;code&gt;JsonSerializerContext&lt;/code&gt;, we&#39;ll need to include all types of object that may come as log parameters.&lt;/p&gt;&lt;h3&gt;Things to consider&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Our logger will implement the &lt;code&gt;ILogger&lt;/code&gt; interface.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;We will consider that &lt;code&gt;TState&lt;/code&gt; always inherits from &lt;code&gt;IReadOnlyList&amp;lt;KeyValuePair&amp;lt;string, object?&gt;&gt;&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Let&#39;s filter messages to ignore the ones that are not relevant, and also to not need to include many object types on our &lt;code&gt;JsonSerializerContext&lt;/code&gt;. This is important especially for ASP.NET projects.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In this example, log lines will be printed on the console.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;We&#39;ll use the &lt;a href=https://clef-json.org/ &gt;&lt;strong&gt;CLEF&lt;/strong&gt;&lt;/a&gt; format.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;scopeProvider&lt;/code&gt; is responsible for reading the captured scopes. We&#39;ll use the &lt;code&gt;LoggerExternalScopeProvider&lt;/code&gt; default implementation.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;Code&lt;/h3&gt;&lt;p&gt;On the HostBuilder / WebApplicationBuilder setup (Program.cs):&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;webAppBuilder&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Logging&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    .&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ClearProviders&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    .&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;AddProvider&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;new&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; ClefLoggerProvider&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Logger provider:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; sealed&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; class&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; ClefLoggerProvider&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; : &lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;ILoggerProvider&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    public&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; ILogger&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; CreateLogger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; categoryName&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;        new&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; ClefLogger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;categoryName&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;new&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; LoggerExternalScopeProvider&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; void&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; Dispose&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;() { }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;JsonSerializerContext:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;[&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;JsonSerializable&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;typeof&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Dictionary&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;object&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;?&gt;))]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;[&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;JsonSerializable&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;typeof&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;double&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;))]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;[&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;JsonSerializable&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;typeof&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;long&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;))]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// add types here, like:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;[&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;JsonSerializable&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;typeof&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;WeatherForecast&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;))]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// JSON options&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;[&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;JsonSourceGenerationOptions&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    WriteIndented&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; false&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    PropertyNamingPolicy&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; JsonKnownNamingPolicy&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;CamelCase&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    DefaultIgnoreCondition&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; JsonIgnoreCondition&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;WhenWritingNull&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; partial&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; class&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; AppJsonSrcGenContext&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; : &lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;JsonSerializerContext&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Logger:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; sealed&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; class&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; ClefLogger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    string&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; categoryName&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;    IExternalScopeProvider&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;? &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;scopeProvider&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) : &lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;ILogger&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    private&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; static&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; readonly&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;[] &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;logsToIgnore&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;        &quot;Request starting&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;        &quot;Executing&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;        &quot;Setting HTTP status code&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;        &quot;Executed&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;        &quot;Writing value&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;        &quot;Write content&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;        &quot;Sending file&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;        &quot;Request reached the end of the middleware pipeline without being handled by application code.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    public&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; IDisposable&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;? &lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;BeginScope&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;TState&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt;(&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;TState&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; state&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;        where&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; TState&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; : &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;notnull&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;        scopeProvider&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;?&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Push&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;state&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;??&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; default&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; bool&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; IsEnabled&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;LogLevel&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; logLevel&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&gt;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; true&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    private&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; static&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; bool&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; FilterProperties&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;KeyValuePair&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;object&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;?&gt; &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;kv&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;        kv&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Key&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; !=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;{OriginalFormat}&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;        &amp;&amp;&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; kv&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Value&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; !=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; null&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;        &amp;&amp;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;kv&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Value&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; is&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; string&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; s&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; ?&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; !&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;IsNullOrEmpty&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;s&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;:&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; true&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    private&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; static&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; bool&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; ShouldIgnoreLog&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;? &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;originalFormat&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;        originalFormat&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; is&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; null&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; ||&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; logsToIgnore&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Any&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;originalFormat&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;StartsWith&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; void&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; Log&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;TState&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt;(&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;LogLevel&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; logLevel&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;EventId&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; eventId&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;TState&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; state&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Exception&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;? &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;exception&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Func&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;TState&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Exception&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;?, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt; &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;formatter&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;        if&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;state&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; is&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; not&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; IEnumerable&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;KeyValuePair&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;object&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;?&gt;&gt; &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;msgProps&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;            return&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;? &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;originalFormat&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;?)&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;msgProps&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;FirstOrDefault&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;kv&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&gt;&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; kv&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Key&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; ==&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;{OriginalFormat}&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;).&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Value&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;        if&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ShouldIgnoreLog&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;originalFormat&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;            return&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;        List&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;IEnumerable&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;KeyValuePair&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;object&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;?&gt;&gt;&gt;? &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;scopes&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; new&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;        scopeProvider&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;?&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ForEachScope&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;((&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;scope&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;st&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;            if&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;scope&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; is&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; IEnumerable&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;KeyValuePair&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;object&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;?&gt;&gt; &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;scopeItems&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;                scopes&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Add&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;scopeItems&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Where&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;FilterProperties&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        }, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;state&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;        IEnumerable&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;KeyValuePair&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;object&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;?&gt;&gt; &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;standardProps&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        [&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;            new&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;@i&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;eventId&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;            new&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;@t&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;DateTime&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;UtcNow&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ToString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;yyyy-MM-ddTHH:mm:ss.fffffffZ&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;            new&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;@c&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;categoryName&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;            new&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;@l&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Enum&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;GetName&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;logLevel&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;            //new(&quot;@m&quot;, formatter(state, exception)),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;            new&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;@mt&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;originalFormat&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;            new&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;@x&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;exception&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;?&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ToString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;        var&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; msg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; standardProps&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;            .&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Concat&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;msgProps&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Where&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;FilterProperties&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;            .&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Concat&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;scopes&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;SelectMany&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&gt;&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; x&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;            // avoiding repeated keys&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;            .&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;DistinctBy&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;kv&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&gt;&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; kv&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Key&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;            // removing null values for JSON&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;            .&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Where&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&gt;&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; x&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Value&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; is&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; not&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; null&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;            .&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ToDictionary&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;        try&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;            WriteLogLine&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;msg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;        catch&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Exception&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; jsonEx&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;            msg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; standardProps&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;                .&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Append&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;new&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;WARNING&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Could not serialize original message to JSON.&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;                .&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Append&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;new&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;JsonException&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;jsonEx&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ToString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;()))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;                // removing null values for JSON&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;                .&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Where&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&gt;&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; x&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Value&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; is&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; not&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; null&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;                .&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ToDictionary&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;            WriteLogLine&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;msg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    // TODO: Use queue to avoid concurrency&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    // Change output if you want: file, logging engine, etc.&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    private&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; void&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; WriteLogLine&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Dictionary&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;object&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;?&gt; &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;msg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        string&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; json&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; JsonSerializer&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Serialize&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;msg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;AppJsonSrcGenContext&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Default&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;DictionaryStringObject&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;        Console&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;WriteLine&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;json&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The logger above works with NativeAOT and trimming enabled.&lt;/p&gt;&lt;p&gt;If there is any JSON serialization error, the catch clause formats a new log message without extra properties and scopes (that may be responsible for the error) and inserts the JsonException related to the problem.&lt;/p&gt;&lt;h3&gt;Example of generated log&lt;/h3&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;@t&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;2025-04-15T12:09:58.4990143Z&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;@c&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Microsoft.AspNetCore.Hosting.Diagnostics&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;@l&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Information&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;@mt&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Request finished {Protocol} {Method} {Scheme}://{Host}{PathBase}{Path}{QueryString} - {StatusCode} {ContentLength} {ContentType} {ElapsedMilliseconds}ms&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;ElapsedMilliseconds&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;124.2172&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;StatusCode&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;201&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;ContentType&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;application/json; charset=utf-8&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;Protocol&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;HTTP/2&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;Method&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;POST&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;Scheme&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;https&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;Host&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;localhost:5001&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;Path&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;RequestId&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;0HNBS2ORC5B08:00000001&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#0451a5;--shiki-dark:#62A6CA&gt;  &quot;RequestPath&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;/&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=sources-and-interesting-reads tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/04/structured-logging-in-dotnet-with-nativeaot/#sources-and-interesting-reads class=header-anchor&gt;&lt;span&gt;Sources and interesting reads&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/ &gt;Microsoft Learn - .NET Native AOT Deployment&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options&gt;Microsoft Learn - .NET Trimming options&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/aspnet/core/fundamentals/native-aot&gt;Microsoft Learn - ASP.NET Core support for Native AOT&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://messagetemplates.org/ &gt;Message Templates&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://clef-json.org/ &gt;Compact Log Event Format (CLEF)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Least squares fitting with functional programming</title>
    <link href="https://alexandrehtrb.github.io/posts/2025/03/least-squares-fitting-with-functional-programming/" />
    <updated>2025-03-07T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2025/03/least-squares-fitting-with-functional-programming/</id>
    <content type="html">&lt;p&gt;Let&#39;s suppose you have a dataset of numerical values and you would like to make a future estimate based on them. Some real-life applications include:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Product pricing;&lt;/li&gt;&lt;li&gt;Historical production and demand;&lt;/li&gt;&lt;li&gt;Financial assets valuation;&lt;/li&gt;&lt;li&gt;Calibration of a machine through time;&lt;/li&gt;&lt;li&gt;Concentration of chemical reagents and products;&lt;/li&gt;&lt;li&gt;Disease transmission rates;&lt;/li&gt;&lt;li&gt;Water reservoir levels;&lt;/li&gt;&lt;li&gt;Electricity demand;&lt;/li&gt;&lt;li&gt;Fuel consumption.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The least squares fitting is a mathematical tool that generates an equation close to existing measurements. Many types of curves can be used, such as linear, polynomial, exponential, logarithmic, and many others.&lt;/p&gt;&lt;p&gt;Consider the graph below, sales per month. The blue line is the linear approximation and the red line corresponds to the real values.&lt;/p&gt;&lt;pre&gt;&lt;code class=language-mermaid&gt;&lt;div class=mermaid&gt;---
config:
    xyChart:
        width: 540
    themeVariables:
        xyChart:
            backgroundColor: &quot;#00000000&quot;
            plotColorPalette: &quot;#C00, #22F&quot;
---
xychart-beta
    title &quot;Sales per month ($)&quot;
    x-axis &quot;month&quot; [1,2,3,4,5,6,7,8,9,10,11,12]
    y-axis 0 --&gt; 50000
    line [17000, 24000, 16000, 30000, 35000, 26000, 29000, 40000, 44000, 35000, 41000, 47000]
	line [18461.538, 20923.076, 23384.614, 25846.152, 28307.690, 30769.228, 33230.766, 35692.304, 38153.842, 40615.380, 43076.918, 45538.456]
	%% =2461,538 * x + 16000

&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;h1 id=theory tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/03/least-squares-fitting-with-functional-programming/#theory class=header-anchor&gt;&lt;span&gt;Theory&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;Consider &lt;strong&gt;f(x)&lt;/strong&gt; the equation we want to generate and &lt;strong&gt;(x&lt;sub&gt;i&lt;/sub&gt;, y&lt;sub&gt;i&lt;/sub&gt;)&lt;/strong&gt; the measurements we have. The best equation is the one where the differences between approximations and measurements are the smallest possible; in other words:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;|f(x&lt;sub&gt;i&lt;/sub&gt;) − y&lt;sub&gt;i&lt;/sub&gt;|&lt;/strong&gt; is the distance between approximation and reality;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Σ&lt;/strong&gt; is the summation.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Σ|f(x&lt;sub&gt;i&lt;/sub&gt;) − y&lt;sub&gt;i&lt;/sub&gt;|&lt;/strong&gt; should be the closest to zero.&lt;/li&gt;&lt;/ul&gt;&lt;img alt=&quot;Differences between approximations and measurements.&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2025_03_least_ordinary_squares_errors.png&gt;&lt;p&gt;Let&#39;s name SSE the sum of squared errors: &lt;strong&gt;SSE = Σ(f(x&lt;sub&gt;i&lt;/sub&gt;) − y&lt;sub&gt;i&lt;/sub&gt;)&lt;sup&gt;2&lt;/sup&gt;&lt;/strong&gt;. As our objective is to measure the distance between approximation and reality, it&#39;s easier to simply power square the difference, instead of applying the absolute function.&lt;/p&gt;&lt;p&gt;&lt;em&gt;We need to apply an absolute or power square operation for distance measurement because a simple subtraction could result in a negative value, which isn&#39;t valid for distances.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;The minimum of SSE depends on the type of desired approximation:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Linear: &lt;strong&gt;f(x) = ax + b&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Exponential: &lt;strong&gt;f(x) = a ⋅ e&lt;sup&gt;bx&lt;/sup&gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Power law: &lt;strong&gt;f(x) = ax&lt;sup&gt;b&lt;/sup&gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Logarithmic: &lt;strong&gt;f(x) = a + b ⋅ ln(x)&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Substituting f(x) by the functions above in SSE, we&#39;ll see that it depends on variables a and b. In the case of linear approximation: &lt;strong&gt;SSE(a,b) = Σ(ax&lt;sub&gt;i&lt;/sub&gt; + b − y&lt;sub&gt;i&lt;/sub&gt;)&lt;sup&gt;2&lt;/sup&gt;&lt;/strong&gt;. x&lt;sub&gt;i&lt;/sub&gt; and y&lt;sub&gt;i&lt;/sub&gt; are constants, due to being known values.&lt;/p&gt;&lt;p&gt;The minimum of a function happens on the point where its derivative (slope) equals zero:&lt;/p&gt;&lt;pre&gt;&lt;code class=language-mermaid&gt;&lt;div class=mermaid&gt;---
config:
    xyChart:
        width: 540
    themeVariables:
        xyChart:
            backgroundColor: &quot;#00000000&quot;
            plotColorPalette: &quot;#CC0000, #f59316, #f59316, #f59316&quot;
---
xychart-beta
    title &quot;y = x²&quot;
    x-axis &quot;x&quot; -6 --&gt; 6
    y-axis &quot;y&quot; 0 --&gt; 40
    line [36,25,16,9,4,1,0,1,4,9,16,25,36]
	line [27,21,15,9,3,-3,-9,-15,-21,-27,-33,-39,-45]
    line [0,0,0,0,0,0,0,0,0,0,0]
    line [-45,-39,-33,-27,-21,-15,-9,-3,3,9,15,21,27]

&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em class=&quot;italic text-sm&quot;&gt;In red: y = x². In orange: the derivatives (slopes) for x = −3, 0 and 3.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;SSE will have its minimum point where the partial derivatives relative to &lt;strong&gt;a&lt;/strong&gt; and &lt;strong&gt;b&lt;/strong&gt; are zero, solving the following system:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;∂SQE(a,b) / ∂a = 0&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;∂SQE(a,b) / ∂b = 0&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;This is the basics for the least squares fitting method. If you are interested and would like to know more, there are links in the end of this page with additional explanations on this topic. Particularly, I recommend this &lt;a href=https://brownmath.com/stat/leastsq.htm&gt;lesson by Stan Brown&lt;/a&gt;.&lt;/p&gt;&lt;br&gt;&lt;h1 id=functional-programming tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/03/least-squares-fitting-with-functional-programming/#functional-programming class=header-anchor&gt;&lt;span&gt;Functional programming&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;Functional programming is a paradigm that focuses on data transformations: like in a mathematical function, a value &lt;strong&gt;x&lt;/strong&gt; is transformed by &lt;strong&gt;f(x)&lt;/strong&gt;. In functional code, transformations are often chained, e.g., &lt;strong&gt;f(g(h(x)))&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;In this article, we will use the F# language, that uses the &lt;a href=https://dotnet.microsoft.com&gt;.NET runtime&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;This &lt;a href=https://alexandrehtrb.github.io/posts/2024/06/introduction-to-functional-programming/#f%23-language&gt;post&lt;/a&gt; explains how to set up your environment and contains tips on the language syntax.&lt;/p&gt;&lt;br&gt;&lt;h1 id=linear-approximation tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/03/least-squares-fitting-with-functional-programming/#linear-approximation class=header-anchor&gt;&lt;span&gt;Linear approximation&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The equation will be &lt;strong&gt;f(x) = ax + b&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;From a set of values (x&lt;sub&gt;i&lt;/sub&gt;, y&lt;sub&gt;i&lt;/sub&gt;), a and b are determined by:&lt;/p&gt;&lt;br&gt;&lt;p&gt;&lt;svg aria-hidden=true focusable=false height=60px role=img style=vertical-align:-2.194ex viewBox=&quot;0 -1460 10250.3 2429.9&quot; width=90% xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink&gt;&lt;defs&gt;&lt;path d=&quot;M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z&quot; id=MJX-1-TEX-I-1D44E&gt;&lt;/path&gt;&lt;path d=&quot;M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z&quot; id=MJX-1-TEX-N-3D&gt;&lt;/path&gt;&lt;path d=&quot;M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z&quot; id=MJX-1-TEX-I-1D45B&gt;&lt;/path&gt;&lt;path d=&quot;M61 748Q64 750 489 750H913L954 640Q965 609 976 579T993 533T999 516H979L959 517Q936 579 886 621T777 682Q724 700 655 705T436 710H319Q183 710 183 709Q186 706 348 484T511 259Q517 250 513 244L490 216Q466 188 420 134T330 27L149 -187Q149 -188 362 -188Q388 -188 436 -188T506 -189Q679 -189 778 -162T936 -43Q946 -27 959 6H999L913 -249L489 -250Q65 -250 62 -248Q56 -246 56 -239Q56 -234 118 -161Q186 -81 245 -11L428 206Q428 207 242 462L57 717L56 728Q56 744 61 748Z&quot; id=MJX-1-TEX-SO-2211&gt;&lt;/path&gt;&lt;path d=&quot;M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z&quot; id=MJX-1-TEX-I-1D465&gt;&lt;/path&gt;&lt;path d=&quot;M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z&quot; id=MJX-1-TEX-I-1D466&gt;&lt;/path&gt;&lt;path d=&quot;M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z&quot; id=MJX-1-TEX-N-2212&gt;&lt;/path&gt;&lt;path d=&quot;M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z&quot; id=MJX-1-TEX-N-32&gt;&lt;/path&gt;&lt;path d=&quot;M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z&quot; id=MJX-1-TEX-N-28&gt;&lt;/path&gt;&lt;path d=&quot;M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z&quot; id=MJX-1-TEX-N-29&gt;&lt;/path&gt;&lt;/defs&gt;&lt;g transform=scale(1,-1) fill=currentColor stroke=currentColor stroke-width=0&gt;&lt;g data-mml-node=math&gt;&lt;g data-mml-node=mi&gt;&lt;use data-c=1D44E xlink:href=#MJX-1-TEX-I-1D44E&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(806.8,0)&gt;&lt;use data-c=3D xlink:href=#MJX-1-TEX-N-3D&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mfrac transform=translate(1862.6,0)&gt;&lt;g data-mml-node=mrow transform=translate(220,710)&gt;&lt;g data-mml-node=mi&gt;&lt;use data-c=1D45B xlink:href=#MJX-1-TEX-I-1D45B&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(766.7,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-1-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(1989.3,0)&gt;&lt;use data-c=1D465 xlink:href=#MJX-1-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(2561.3,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-1-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(3273.6,0)&gt;&lt;use data-c=2212 xlink:href=#MJX-1-TEX-N-2212&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(4273.8,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-1-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(5496.4,0)&gt;&lt;use data-c=1D465 xlink:href=#MJX-1-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(6235.1,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-1-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(7457.8,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-1-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=mrow transform=translate(579.1,-719.9)&gt;&lt;g data-mml-node=mi&gt;&lt;use data-c=1D45B xlink:href=#MJX-1-TEX-I-1D45B&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(766.7,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-1-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=msup transform=translate(1989.3,0)&gt;&lt;g data-mml-node=mi&gt;&lt;use data-c=1D465 xlink:href=#MJX-1-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mn transform=&quot;translate(605,289) scale(0.707)&quot;&gt;&lt;use data-c=32 xlink:href=#MJX-1-TEX-N-32&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(3220.1,0)&gt;&lt;use data-c=2212 xlink:href=#MJX-1-TEX-N-2212&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(4220.3,0)&gt;&lt;use data-c=28 xlink:href=#MJX-1-TEX-N-28&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(4609.3,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-1-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(5832,0)&gt;&lt;use data-c=1D465 xlink:href=#MJX-1-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=msup transform=translate(6404,0)&gt;&lt;g data-mml-node=mo&gt;&lt;use data-c=29 xlink:href=#MJX-1-TEX-N-29&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mn transform=&quot;translate(422,289) scale(0.707)&quot;&gt;&lt;use data-c=32 xlink:href=#MJX-1-TEX-N-32&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;rect height=60 width=8147.8 x=120 y=220&gt;&lt;/rect&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/p&gt;&lt;br&gt;&lt;p&gt;&lt;svg aria-hidden=true focusable=false height=60px role=img style=vertical-align:-2.194ex viewBox=&quot;0 -1543.9 11781.6 2513.9&quot; width=90% xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink&gt;&lt;defs&gt;&lt;path d=&quot;M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z&quot; id=MJX-3-TEX-I-1D44F&gt;&lt;/path&gt;&lt;path d=&quot;M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z&quot; id=MJX-3-TEX-N-3D&gt;&lt;/path&gt;&lt;path d=&quot;M61 748Q64 750 489 750H913L954 640Q965 609 976 579T993 533T999 516H979L959 517Q936 579 886 621T777 682Q724 700 655 705T436 710H319Q183 710 183 709Q186 706 348 484T511 259Q517 250 513 244L490 216Q466 188 420 134T330 27L149 -187Q149 -188 362 -188Q388 -188 436 -188T506 -189Q679 -189 778 -162T936 -43Q946 -27 959 6H999L913 -249L489 -250Q65 -250 62 -248Q56 -246 56 -239Q56 -234 118 -161Q186 -81 245 -11L428 206Q428 207 242 462L57 717L56 728Q56 744 61 748Z&quot; id=MJX-3-TEX-SO-2211&gt;&lt;/path&gt;&lt;path d=&quot;M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z&quot; id=MJX-3-TEX-I-1D466&gt;&lt;/path&gt;&lt;path d=&quot;M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z&quot; id=MJX-3-TEX-I-1D465&gt;&lt;/path&gt;&lt;path d=&quot;M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z&quot; id=MJX-3-TEX-N-32&gt;&lt;/path&gt;&lt;path d=&quot;M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z&quot; id=MJX-3-TEX-N-2212&gt;&lt;/path&gt;&lt;path d=&quot;M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z&quot; id=MJX-3-TEX-I-1D45B&gt;&lt;/path&gt;&lt;path d=&quot;M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z&quot; id=MJX-3-TEX-N-28&gt;&lt;/path&gt;&lt;path d=&quot;M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z&quot; id=MJX-3-TEX-N-29&gt;&lt;/path&gt;&lt;/defs&gt;&lt;g transform=scale(1,-1) fill=currentColor stroke=currentColor stroke-width=0&gt;&lt;g data-mml-node=math&gt;&lt;g data-mml-node=mi&gt;&lt;use data-c=1D44F xlink:href=#MJX-3-TEX-I-1D44F&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(706.8,0)&gt;&lt;use data-c=3D xlink:href=#MJX-3-TEX-N-3D&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mfrac transform=translate(1762.6,0)&gt;&lt;g data-mml-node=mrow transform=translate(220,710)&gt;&lt;g data-mml-node=mo&gt;&lt;use data-c=2211 xlink:href=#MJX-3-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(1222.7,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-3-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(1879.3,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-3-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=msup transform=translate(3102,0)&gt;&lt;g data-mml-node=mi&gt;&lt;use data-c=1D465 xlink:href=#MJX-3-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mn transform=&quot;translate(605,363) scale(0.707)&quot;&gt;&lt;use data-c=32 xlink:href=#MJX-3-TEX-N-32&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(4332.8,0)&gt;&lt;use data-c=2212 xlink:href=#MJX-3-TEX-N-2212&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(5333,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-3-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(6555.7,0)&gt;&lt;use data-c=1D465 xlink:href=#MJX-3-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(7127.7,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-3-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(7784.3,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-3-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(9007,0)&gt;&lt;use data-c=1D465 xlink:href=#MJX-3-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=mrow transform=translate(1394.7,-719.9)&gt;&lt;g data-mml-node=mi&gt;&lt;use data-c=1D45B xlink:href=#MJX-3-TEX-I-1D45B&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(766.7,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-3-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=msup transform=translate(1989.3,0)&gt;&lt;g data-mml-node=mi&gt;&lt;use data-c=1D465 xlink:href=#MJX-3-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mn transform=&quot;translate(605,289) scale(0.707)&quot;&gt;&lt;use data-c=32 xlink:href=#MJX-3-TEX-N-32&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(3220.1,0)&gt;&lt;use data-c=2212 xlink:href=#MJX-3-TEX-N-2212&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(4220.3,0)&gt;&lt;use data-c=28 xlink:href=#MJX-3-TEX-N-28&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(4609.3,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-3-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(5832,0)&gt;&lt;use data-c=1D465 xlink:href=#MJX-3-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=msup transform=translate(6404,0)&gt;&lt;g data-mml-node=mo&gt;&lt;use data-c=29 xlink:href=#MJX-3-TEX-N-29&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mn transform=&quot;translate(422,289) scale(0.707)&quot;&gt;&lt;use data-c=32 xlink:href=#MJX-3-TEX-N-32&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;rect height=60 width=9779 x=120 y=220&gt;&lt;/rect&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/p&gt;&lt;br&gt;&lt;p&gt;The F# code below calculates the linear approximation.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; are the input values.&lt;/li&gt;&lt;li&gt;&lt;code&gt;Seq.sumBy&lt;/code&gt; sums the results of a function applied over elements of a sequence:&lt;ul&gt;&lt;li&gt;&lt;code&gt;x = [1, 2, 3]&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;x |&gt; Seq.sumBy(fun i -&gt; 2 * i) = 12&lt;/code&gt;&lt;/li&gt;&lt;li&gt;(2*1 + 2*2 + 2*3 = 12)&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;Seq.zip&lt;/code&gt; makes a sequence of pairs coming from two other sequences:&lt;ul&gt;&lt;li&gt;&lt;code&gt;x = [1, 2, 3]&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;y = [9, 8, 7]&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;Seq.zip(x)(y) = [ (1, 9), (2, 8), (3, 7) ]&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// s = sum&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; s&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[]):&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    v &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;|&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.sum&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// sm = sum of multiplications&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sm&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[])(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[]):&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    Seq.zip&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;v1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;v2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.sumBy &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(fun&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; x &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; linearApproximation&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[])(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[]):&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;double &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;) =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; n&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; x.Length &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;|&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; double&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sx&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; s&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sx2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; sm&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; s&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sxy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; sm&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; d&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; n&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sx2 &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; sx&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;**&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; a&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;n&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sxy &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; sx&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)/&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;d&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; b&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sx2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sy &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; sxy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sx&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)/&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;d&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;a&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;b&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;h1 id=exponential-approximation tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/03/least-squares-fitting-with-functional-programming/#exponential-approximation class=header-anchor&gt;&lt;span&gt;Exponential approximation&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The equation will be &lt;strong&gt;f(x) = A ⋅ e&lt;sup&gt;bx&lt;/sup&gt;&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;e&lt;/strong&gt; is the &lt;a href=https://en.wikipedia.org/wiki/E_(mathematical_constant)&gt;natural base&lt;/a&gt;, approximately equal to 2.71828.&lt;/p&gt;&lt;p&gt;From a set of values (x&lt;sub&gt;i&lt;/sub&gt;, y&lt;sub&gt;i&lt;/sub&gt;), a and b are determined by:&lt;/p&gt;&lt;br&gt;&lt;p&gt;&lt;svg aria-hidden=true focusable=false height=60px role=img style=vertical-align:-2.194ex viewBox=&quot;0 -1543.9 18621.6 2513.9&quot; width=90% xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink&gt;&lt;defs&gt;&lt;path d=&quot;M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z&quot; id=MJX-4-TEX-I-1D44E&gt;&lt;/path&gt;&lt;path d=&quot;M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z&quot; id=MJX-4-TEX-N-3D&gt;&lt;/path&gt;&lt;path d=&quot;M61 748Q64 750 489 750H913L954 640Q965 609 976 579T993 533T999 516H979L959 517Q936 579 886 621T777 682Q724 700 655 705T436 710H319Q183 710 183 709Q186 706 348 484T511 259Q517 250 513 244L490 216Q466 188 420 134T330 27L149 -187Q149 -188 362 -188Q388 -188 436 -188T506 -189Q679 -189 778 -162T936 -43Q946 -27 959 6H999L913 -249L489 -250Q65 -250 62 -248Q56 -246 56 -239Q56 -234 118 -161Q186 -81 245 -11L428 206Q428 207 242 462L57 717L56 728Q56 744 61 748Z&quot; id=MJX-4-TEX-SO-2211&gt;&lt;/path&gt;&lt;path d=&quot;M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z&quot; id=MJX-4-TEX-N-28&gt;&lt;/path&gt;&lt;path d=&quot;M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z&quot; id=MJX-4-TEX-I-1D465&gt;&lt;/path&gt;&lt;path d=&quot;M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z&quot; id=MJX-4-TEX-N-32&gt;&lt;/path&gt;&lt;path d=&quot;M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z&quot; id=MJX-4-TEX-I-1D466&gt;&lt;/path&gt;&lt;path d=&quot;M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z&quot; id=MJX-4-TEX-N-29&gt;&lt;/path&gt;&lt;path d=&quot;M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z&quot; id=MJX-4-TEX-N-6C&gt;&lt;/path&gt;&lt;path d=&quot;M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z&quot; id=MJX-4-TEX-N-6E&gt;&lt;/path&gt;&lt;path d=&quot;&quot; id=MJX-4-TEX-N-2061&gt;&lt;/path&gt;&lt;path d=&quot;M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z&quot; id=MJX-4-TEX-N-2212&gt;&lt;/path&gt;&lt;/defs&gt;&lt;g transform=scale(1,-1) fill=currentColor stroke=currentColor stroke-width=0&gt;&lt;g data-mml-node=math&gt;&lt;g data-mml-node=mi&gt;&lt;use data-c=1D44E xlink:href=#MJX-4-TEX-I-1D44E&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(806.8,0)&gt;&lt;use data-c=3D xlink:href=#MJX-4-TEX-N-3D&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mfrac transform=translate(1862.6,0)&gt;&lt;g data-mml-node=mrow transform=translate(220,710)&gt;&lt;g data-mml-node=mo&gt;&lt;use data-c=2211 xlink:href=#MJX-4-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(1056,0)&gt;&lt;use data-c=28 xlink:href=#MJX-4-TEX-N-28&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=msup transform=translate(1445,0)&gt;&lt;g data-mml-node=mi&gt;&lt;use data-c=1D465 xlink:href=#MJX-4-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mn transform=&quot;translate(605,363) scale(0.707)&quot;&gt;&lt;use data-c=32 xlink:href=#MJX-4-TEX-N-32&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(2453.6,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-4-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(2943.6,0)&gt;&lt;use data-c=29 xlink:href=#MJX-4-TEX-N-29&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(3499.2,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-4-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(4555.2,0)&gt;&lt;use data-c=28 xlink:href=#MJX-4-TEX-N-28&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(4944.2,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-4-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(5600.9,0)&gt;&lt;use data-c=6C xlink:href=#MJX-4-TEX-N-6C&gt;&lt;/use&gt;&lt;use data-c=6E xlink:href=#MJX-4-TEX-N-6E transform=translate(278,0)&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(6434.9,0)&gt;&lt;use data-c=2061 xlink:href=#MJX-4-TEX-N-2061&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(6601.6,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-4-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(7091.6,0)&gt;&lt;use data-c=29 xlink:href=#MJX-4-TEX-N-29&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(7702.8,0)&gt;&lt;use data-c=2212 xlink:href=#MJX-4-TEX-N-2212&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(8703,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-4-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(9759,0)&gt;&lt;use data-c=28 xlink:href=#MJX-4-TEX-N-28&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(10148,0)&gt;&lt;use data-c=1D465 xlink:href=#MJX-4-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(10720,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-4-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(11210,0)&gt;&lt;use data-c=29 xlink:href=#MJX-4-TEX-N-29&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(11765.7,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-4-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(12821.7,0)&gt;&lt;use data-c=28 xlink:href=#MJX-4-TEX-N-28&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(13210.7,0)&gt;&lt;use data-c=1D465 xlink:href=#MJX-4-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(13782.7,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-4-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(14439.3,0)&gt;&lt;use data-c=6C xlink:href=#MJX-4-TEX-N-6C&gt;&lt;/use&gt;&lt;use data-c=6E xlink:href=#MJX-4-TEX-N-6E transform=translate(278,0)&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(15273.3,0)&gt;&lt;use data-c=2061 xlink:href=#MJX-4-TEX-N-2061&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(15440,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-4-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(15930,0)&gt;&lt;use data-c=29 xlink:href=#MJX-4-TEX-N-29&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=mrow transform=translate(3412.7,-719.9)&gt;&lt;g data-mml-node=mo&gt;&lt;use data-c=2211 xlink:href=#MJX-4-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(1222.7,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-4-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(1879.3,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-4-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(2935.3,0)&gt;&lt;use data-c=28 xlink:href=#MJX-4-TEX-N-28&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=msup transform=translate(3324.3,0)&gt;&lt;g data-mml-node=mi&gt;&lt;use data-c=1D465 xlink:href=#MJX-4-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mn transform=&quot;translate(605,289) scale(0.707)&quot;&gt;&lt;use data-c=32 xlink:href=#MJX-4-TEX-N-32&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(4332.9,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-4-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(4822.9,0)&gt;&lt;use data-c=29 xlink:href=#MJX-4-TEX-N-29&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(5434.1,0)&gt;&lt;use data-c=2212 xlink:href=#MJX-4-TEX-N-2212&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(6434.3,0)&gt;&lt;use data-c=28 xlink:href=#MJX-4-TEX-N-28&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(6823.3,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-4-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(8046,0)&gt;&lt;use data-c=1D465 xlink:href=#MJX-4-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(8618,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-4-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=msup transform=translate(9108,0)&gt;&lt;g data-mml-node=mo&gt;&lt;use data-c=29 xlink:href=#MJX-4-TEX-N-29&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mn transform=&quot;translate(422,289) scale(0.707)&quot;&gt;&lt;use data-c=32 xlink:href=#MJX-4-TEX-N-32&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;rect height=60 width=16519 x=120 y=220&gt;&lt;/rect&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/p&gt;&lt;br&gt;&lt;p&gt;&lt;svg aria-hidden=true focusable=false height=60px role=img style=vertical-align:-2.194ex viewBox=&quot;0 -1460 16901.7 2429.9&quot; width=90% xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink&gt;&lt;defs&gt;&lt;path d=&quot;M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z&quot; id=MJX-5-TEX-I-1D44F&gt;&lt;/path&gt;&lt;path d=&quot;M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z&quot; id=MJX-5-TEX-N-3D&gt;&lt;/path&gt;&lt;path d=&quot;M61 748Q64 750 489 750H913L954 640Q965 609 976 579T993 533T999 516H979L959 517Q936 579 886 621T777 682Q724 700 655 705T436 710H319Q183 710 183 709Q186 706 348 484T511 259Q517 250 513 244L490 216Q466 188 420 134T330 27L149 -187Q149 -188 362 -188Q388 -188 436 -188T506 -189Q679 -189 778 -162T936 -43Q946 -27 959 6H999L913 -249L489 -250Q65 -250 62 -248Q56 -246 56 -239Q56 -234 118 -161Q186 -81 245 -11L428 206Q428 207 242 462L57 717L56 728Q56 744 61 748Z&quot; id=MJX-5-TEX-SO-2211&gt;&lt;/path&gt;&lt;path d=&quot;M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z&quot; id=MJX-5-TEX-I-1D466&gt;&lt;/path&gt;&lt;path d=&quot;M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z&quot; id=MJX-5-TEX-N-28&gt;&lt;/path&gt;&lt;path d=&quot;M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z&quot; id=MJX-5-TEX-I-1D465&gt;&lt;/path&gt;&lt;path d=&quot;M42 46H56Q95 46 103 60V68Q103 77 103 91T103 124T104 167T104 217T104 272T104 329Q104 366 104 407T104 482T104 542T103 586T103 603Q100 622 89 628T44 637H26V660Q26 683 28 683L38 684Q48 685 67 686T104 688Q121 689 141 690T171 693T182 694H185V379Q185 62 186 60Q190 52 198 49Q219 46 247 46H263V0H255L232 1Q209 2 183 2T145 3T107 3T57 1L34 0H26V46H42Z&quot; id=MJX-5-TEX-N-6C&gt;&lt;/path&gt;&lt;path d=&quot;M41 46H55Q94 46 102 60V68Q102 77 102 91T102 122T103 161T103 203Q103 234 103 269T102 328V351Q99 370 88 376T43 385H25V408Q25 431 27 431L37 432Q47 433 65 434T102 436Q119 437 138 438T167 441T178 442H181V402Q181 364 182 364T187 369T199 384T218 402T247 421T285 437Q305 442 336 442Q450 438 463 329Q464 322 464 190V104Q464 66 466 59T477 49Q498 46 526 46H542V0H534L510 1Q487 2 460 2T422 3Q319 3 310 0H302V46H318Q379 46 379 62Q380 64 380 200Q379 335 378 343Q372 371 358 385T334 402T308 404Q263 404 229 370Q202 343 195 315T187 232V168V108Q187 78 188 68T191 55T200 49Q221 46 249 46H265V0H257L234 1Q210 2 183 2T145 3Q42 3 33 0H25V46H41Z&quot; id=MJX-5-TEX-N-6E&gt;&lt;/path&gt;&lt;path d=&quot;&quot; id=MJX-5-TEX-N-2061&gt;&lt;/path&gt;&lt;path d=&quot;M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z&quot; id=MJX-5-TEX-N-29&gt;&lt;/path&gt;&lt;path d=&quot;M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z&quot; id=MJX-5-TEX-N-2212&gt;&lt;/path&gt;&lt;path d=&quot;M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z&quot; id=MJX-5-TEX-N-32&gt;&lt;/path&gt;&lt;/defs&gt;&lt;g transform=scale(1,-1) fill=currentColor stroke=currentColor stroke-width=0&gt;&lt;g data-mml-node=math&gt;&lt;g data-mml-node=mi&gt;&lt;use data-c=1D44F xlink:href=#MJX-5-TEX-I-1D44F&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(706.8,0)&gt;&lt;use data-c=3D xlink:href=#MJX-5-TEX-N-3D&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mfrac transform=translate(1762.6,0)&gt;&lt;g data-mml-node=mrow transform=translate(220,710)&gt;&lt;g data-mml-node=mo&gt;&lt;use data-c=2211 xlink:href=#MJX-5-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(1222.7,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-5-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(1879.3,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-5-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(2935.3,0)&gt;&lt;use data-c=28 xlink:href=#MJX-5-TEX-N-28&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(3324.3,0)&gt;&lt;use data-c=1D465 xlink:href=#MJX-5-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(3896.3,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-5-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(4553,0)&gt;&lt;use data-c=6C xlink:href=#MJX-5-TEX-N-6C&gt;&lt;/use&gt;&lt;use data-c=6E xlink:href=#MJX-5-TEX-N-6E transform=translate(278,0)&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(5387,0)&gt;&lt;use data-c=2061 xlink:href=#MJX-5-TEX-N-2061&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(5553.7,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-5-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(6043.7,0)&gt;&lt;use data-c=29 xlink:href=#MJX-5-TEX-N-29&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(6654.9,0)&gt;&lt;use data-c=2212 xlink:href=#MJX-5-TEX-N-2212&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(7655.1,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-5-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(8711.1,0)&gt;&lt;use data-c=28 xlink:href=#MJX-5-TEX-N-28&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(9100.1,0)&gt;&lt;use data-c=1D465 xlink:href=#MJX-5-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(9672.1,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-5-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(10162.1,0)&gt;&lt;use data-c=29 xlink:href=#MJX-5-TEX-N-29&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(10717.8,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-5-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(11773.8,0)&gt;&lt;use data-c=28 xlink:href=#MJX-5-TEX-N-28&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(12162.8,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-5-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(12819.4,0)&gt;&lt;use data-c=6C xlink:href=#MJX-5-TEX-N-6C&gt;&lt;/use&gt;&lt;use data-c=6E xlink:href=#MJX-5-TEX-N-6E transform=translate(278,0)&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(13653.4,0)&gt;&lt;use data-c=2061 xlink:href=#MJX-5-TEX-N-2061&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(13820.1,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-5-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(14310.1,0)&gt;&lt;use data-c=29 xlink:href=#MJX-5-TEX-N-29&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=mrow transform=translate(2602.8,-719.9)&gt;&lt;g data-mml-node=mo&gt;&lt;use data-c=2211 xlink:href=#MJX-5-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(1222.7,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-5-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(1879.3,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-5-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(2935.3,0)&gt;&lt;use data-c=28 xlink:href=#MJX-5-TEX-N-28&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=msup transform=translate(3324.3,0)&gt;&lt;g data-mml-node=mi&gt;&lt;use data-c=1D465 xlink:href=#MJX-5-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mn transform=&quot;translate(605,289) scale(0.707)&quot;&gt;&lt;use data-c=32 xlink:href=#MJX-5-TEX-N-32&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(4332.9,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-5-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(4822.9,0)&gt;&lt;use data-c=29 xlink:href=#MJX-5-TEX-N-29&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(5434.1,0)&gt;&lt;use data-c=2212 xlink:href=#MJX-5-TEX-N-2212&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(6434.3,0)&gt;&lt;use data-c=28 xlink:href=#MJX-5-TEX-N-28&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mo transform=translate(6823.3,0)&gt;&lt;use data-c=2211 xlink:href=#MJX-5-TEX-SO-2211&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(8046,0)&gt;&lt;use data-c=1D465 xlink:href=#MJX-5-TEX-I-1D465&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mi transform=translate(8618,0)&gt;&lt;use data-c=1D466 xlink:href=#MJX-5-TEX-I-1D466&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=msup transform=translate(9108,0)&gt;&lt;g data-mml-node=mo&gt;&lt;use data-c=29 xlink:href=#MJX-5-TEX-N-29&gt;&lt;/use&gt;&lt;/g&gt;&lt;g data-mml-node=mn transform=&quot;translate(422,289) scale(0.707)&quot;&gt;&lt;use data-c=32 xlink:href=#MJX-5-TEX-N-32&gt;&lt;/use&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;rect height=60 width=14899.1 x=120 y=220&gt;&lt;/rect&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/p&gt;&lt;br&gt;&lt;p&gt;The F# code below calculates the exponential approximation.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;ln&lt;/strong&gt; is the natural logarithm, on base &lt;strong&gt;e&lt;/strong&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;A = e&lt;sup&gt;a&lt;/sup&gt;&lt;/strong&gt;.&lt;/li&gt;&lt;li&gt;&lt;code&gt;Seq.zip3&lt;/code&gt; follows the same logic as &lt;code&gt;Seq.zip&lt;/code&gt;, but forms a sequence of groups of three, coming from three other sequences.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Important&lt;/strong&gt;: the values of y need to be all greater than 0, because there is no logarithm of zero or negative numbers.&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// s = sum&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; s&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[]):&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    v &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;|&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.sum&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// sm = sum of multiplications&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sm&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[])(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[]):&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    Seq.zip&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;v1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;v2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.sumBy &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(fun&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; x &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; ln&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; System.Math.Log&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// smm = sum(v1 * v2 * v3)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; smm&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[])(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[])(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v3&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[]):&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    Seq.zip3&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;v1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;v2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;v3&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.sumBy &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(fun&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;a&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;b&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;c&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; a &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; b &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; c&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// smln = sum(v1 * ln(v2))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; smln&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[])(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[]):&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    Seq.zip&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;v1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;v2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.sumBy &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(fun&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;a&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;b&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; a &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; ln&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;b&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// smmln = sum(v1 * v2 * ln(v3))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; smmln&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[])(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[])(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;v3&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[]):&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    Seq.zip3&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;v1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;v2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;v3&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.sumBy &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(fun&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;a&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;b&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;c&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; a &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; b &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; ln&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// exponential: y = A * e^(b*x)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; exponentialApproximation&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[])(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;[]):&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;double &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; double&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;) =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sx2y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; smm&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sylny&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; smln&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sxy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; sm&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sxylny&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; smmln&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; s&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; d&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; sy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sx2y &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; sxy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;**&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; a&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sx2y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sylny &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; sxy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sxylny&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)/&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;d&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; b&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sxylny &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; sxy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sylny&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)/&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;d&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; A&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; System.Math.Exp&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;a&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;A&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; b&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;h1 id=case-study%3A-silver-mining tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/03/least-squares-fitting-with-functional-programming/#case-study%3A-silver-mining class=header-anchor&gt;&lt;span&gt;Case study: Silver mining&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;img alt=&quot;&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2025_03_argentina_pirquitas_silver_mine.jpg&gt;&lt;p&gt;&lt;em class=&quot;italic text-sm&quot;&gt;Pirquitas mine, Jujuy, Argentina.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Let&#39;s extract data from the &lt;a href=https://ourworldindata.org/metals-minerals&gt;Our World in Data&lt;/a&gt; website on world silver mining production, between 1900 and 2023, and let&#39;s make the linear and exponential approximations.&lt;/p&gt;&lt;p&gt;CSV data available &lt;a href=https://alexandrehtrb.github.io/assets/misc/1900-2023-silver_mining_production.csv&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Results:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;f(x)&lt;/strong&gt; is the mining production in metric tonnes, x is the year.&lt;/li&gt;&lt;li&gt;Linear: &lt;strong&gt;f(x) = 162.897x − 308090.816&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Exponential: &lt;strong&gt;f(x) = 0.000000002257 ⋅ e&lt;sup&gt;0.01485166x&lt;/sup&gt;&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=language-mermaid&gt;&lt;div class=mermaid&gt;---
config:
    xyChart:
        width: 540
    themeVariables:
        xyChart:
            backgroundColor: &quot;#00000000&quot;
            plotColorPalette: &quot;#CC0000, #2222FF, #00CC00&quot;
---
xychart-beta
    title &quot;Silver mining production (metric tonnes)&quot;
    x-axis &quot;Year&quot; 1900 --&gt; 2023
    y-axis 0 --&gt; 30000
    line [ 5400, 5380, 5060, 5220, 5110, 5360, 5130, 5730, 6320, 6600, 6900, 7040, 6980, 7010, 5240, 5730, 5250, 5420, 6140, 5490, 5390, 5330, 6530, 7650, 7450, 7650, 7890, 7900, 8020, 8120, 7740, 6080, 5130, 5340, 5990, 6890, 7920, 8640, 8320, 8300, 8570, 8140, 7780, 6380, 5740, 5040, 3970, 5220, 5440, 5570, 6320, 6210, 6700, 6900, 6670, 7000, 7020, 7190, 7430, 6910, 7320, 7370, 7650, 7780, 7730, 8010, 8300, 8030, 8560, 9200, 9360, 9170, 9380, 9700, 9260, 9430, 9840, 10300, 10700, 10800, 10700, 11200, 11500, 12100, 13100, 13100, 13000, 14000, 15500, 16400, 16600, 15600, 14900, 14100, 14000, 14900, 15100, 16500, 17200, 17600, 18100, 18700, 18800, 18800, 20000, 20800, 20100, 20800, 21300, 22300, 23300, 23300, 24300, 26700, 28000, 27600, 28600, 26500, 25900, 25800, 23500, 25000, 25600, 26000 ]
	line [ 1413.484, 1576.381, 1739.278, 1902.175, 2065.072, 2227.969, 2390.866, 2553.763, 2716.66, 2879.557, 3042.454, 3205.351, 3368.248, 3531.145, 3694.042, 3856.939, 4019.836, 4182.733, 4345.63, 4508.527, 4671.424, 4834.321, 4997.218, 5160.115, 5323.012, 5485.909, 5648.806, 5811.703, 5974.6, 6137.497, 6300.394, 6463.291, 6626.188, 6789.085, 6951.982, 7114.879, 7277.776, 7440.673, 7603.57, 7766.467, 7929.364, 8092.261, 8255.158, 8418.055, 8580.952, 8743.849, 8906.746, 9069.643, 9232.54, 9395.437, 9558.334, 9721.231, 9884.128, 10047.025, 10209.922, 10372.819, 10535.716, 10698.613, 10861.51, 11024.407, 11187.304, 11350.201, 11513.098, 11675.995, 11838.892, 12001.789, 12164.686, 12327.583, 12490.48, 12653.377, 12816.274, 12979.171, 13142.068, 13304.965, 13467.862, 13630.759, 13793.656, 13956.553, 14119.45, 14282.347, 14445.244, 14608.141, 14771.038, 14933.935, 15096.832, 15259.729, 15422.626, 15585.523, 15748.42, 15911.317, 16074.214, 16237.111, 16400.008, 16562.905, 16725.802, 16888.699, 17051.596, 17214.493, 17377.39, 17540.287, 17703.184, 17866.081, 18028.978, 18191.875, 18354.772, 18517.669, 18680.566, 18843.463, 19006.36, 19169.257, 19332.154, 19495.051, 19657.948, 19820.845, 19983.742, 20146.639, 20309.536, 20472.433, 20635.33, 20798.227, 20961.124, 21124.021, 21286.918, 21449.815 ]
	line [ 4059.94, 4120.69, 4182.34, 4244.92, 4308.44, 4372.90, 4438.33, 4504.74, 4572.14, 4640.55, 4709.99, 4780.46, 4851.99, 4924.58, 4998.27, 5073.06, 5148.96, 5226.00, 5304.20, 5383.56, 5464.11, 5545.87, 5628.85, 5713.07, 5798.55, 5885.31, 5973.37, 6062.75, 6153.46, 6245.53, 6338.98, 6433.83, 6530.10, 6627.80, 6726.97, 6827.62, 6929.78, 7033.47, 7138.71, 7245.52, 7353.93, 7463.96, 7575.64, 7689.00, 7804.04, 7920.81, 8039.32, 8159.61, 8281.70, 8405.62, 8531.39, 8659.04, 8788.60, 8920.10, 9053.56, 9189.03, 9326.52, 9466.07, 9607.70, 9751.46, 9897.36, 10045.45, 10195.76, 10348.31, 10503.15, 10660.30, 10819.81, 10981.70, 11146.01, 11312.78, 11482.05, 11653.85, 11828.22, 12005.20, 12184.83, 12367.15, 12552.19, 12740.00, 12930.62, 13124.10, 13320.47, 13519.78, 13722.07, 13927.38, 14135.77, 14347.28, 14561.95, 14779.83, 15000.97, 15225.43, 15453.24, 15684.46, 15919.13, 16157.32, 16399.08, 16644.45, 16893.49, 17146.26, 17402.81, 17663.20, 17927.49, 18195.73, 18467.98, 18744.31, 19024.77, 19309.43, 19598.34, 19891.58, 20189.21, 20491.29, 20797.89, 21109.08, 21424.93, 21745.50, 22070.86, 22401.10, 22736.28, 23076.47, 23421.75, 23772.20, 24127.89, 24488.90, 24855.32, 25227.21 ]
	%% linear: 162,897 * year - 308090,816
	%% exponential: =(0,000000002257)*e^(year*0,01485166)

&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em class=&quot;italic text-sm&quot;&gt;Red line: year production; blue line: linear approximation; green line: exponential approximation.&lt;/em&gt;&lt;/p&gt;&lt;br&gt;&lt;h1 id=sources-and-interesting-reads tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/03/least-squares-fitting-with-functional-programming/#sources-and-interesting-reads class=header-anchor&gt;&lt;span&gt;Sources and interesting reads&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://brownmath.com/stat/leastsq.htm&gt;Stan Brown - Least Squares — the Gory Details&lt;/a&gt; (&lt;a href=https://alexandrehtrb.github.io/assets/misc/least_squares_fitting_lesson.html&gt;backup&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href=https://www.cs.princeton.edu/courses/archive/fall11/cos323/notes/cos323_f11_lecture07_lsq.pdf&gt;Princeton University - Data Modeling and Least Squares Fitting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://uregina.ca/~kozdron/Teaching/Regina/252Winter05/Handouts/least_squares.pdf&gt;University of Regina - Linear Regression and Least Squares&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://mathworld.wolfram.com/LeastSquaresFitting.html&gt;Wolfram MathWorld - Least Squares Fitting, Linear&lt;/a&gt; (&lt;a href=https://web.archive.org/web/20250228131909/https://mathworld.wolfram.com/LeastSquaresFitting.html&gt;WebArchive&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href=https://mathworld.wolfram.com/LeastSquaresFittingExponential.html&gt;Wolfram MathWorld - Least Squares Fitting, Exponential&lt;/a&gt; (&lt;a href=https://web.archive.org/web/20250212183347/https://mathworld.wolfram.com/LeastSquaresFittingExponential.html&gt;WebArchive&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href=https://mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html&gt;Wolfram MathWorld - Least Squares Fitting, Power Law&lt;/a&gt; (&lt;a href=https://web.archive.org/web/20250212183356/https://mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html&gt;WebArchive&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href=https://mathworld.wolfram.com/LeastSquaresFittingLogarithmic.html&gt;Wolfram MathWorld - Least Squares Fitting, Logarithmic&lt;/a&gt; (&lt;a href=https://web.archive.org/web/20250212183349/https://mathworld.wolfram.com/LeastSquaresFittingLogarithmic.html&gt;WebArchive&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href=https://www.mathjax.org/ &gt;MathJax - LaTeX renderer&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://ourworldindata.org/metals-minerals&gt;Our World In Data - Metals and Minerals&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://www.mining.com/worlds-top-10-silver-mines/ &gt;Mining.com - World’s top 10 silver mines&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Graphs made with &lt;a href=https://mermaid.live/ &gt;Mermaid.js XY Charts&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Interfaces as a principle of engineering</title>
    <link href="https://alexandrehtrb.github.io/posts/2025/02/interfaces-as-a-principle-of-engineering/" />
    <updated>2025-02-20T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2025/02/interfaces-as-a-principle-of-engineering/</id>
    <content type="html">&lt;p&gt;An interface is how two different things communicate with each other.&lt;/p&gt;&lt;p&gt;In the field of engineering, interfaces are very useful for abstracting the macro logic of a system. With them, components can focus on specific tasks, and interfaces define how they connect to each other.&lt;/p&gt;&lt;pre&gt;&lt;code class=language-mermaid&gt;&lt;div class=mermaid&gt;flowchart LR
  A
  B
  subgraph S[S]
    direction RL
    a
    b
  end
  a-.-&gt;A  
  b-.-&gt;B
  classDef abstract stroke:#f66,stroke-width:2px,stroke-dasharray: 5 5
  class a,b abstract;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em class=&quot;italic text-sm&quot;&gt;In the diagram above, the system S delegates tasks a and b to components A and B, respectively. Arrows represent interfaces.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Let&#39;s analyse here some benefits of interfaces.&lt;/p&gt;&lt;h3&gt;Reuse&lt;/h3&gt;&lt;p&gt;Interfaces enable a component to be designed to support multiple systems.&lt;/p&gt;&lt;h3&gt;Repurposing&lt;/h3&gt;&lt;p&gt;It&#39;s similar to reuse, but reuse is about designing a component to support many use cases; repurposing is about using an existing component, instead of creating a new one.&lt;/p&gt;&lt;h3&gt;Interchangeability&lt;/h3&gt;&lt;p&gt;Parts can be replaced with equivalent ones — from a different supplier, for example.&lt;/p&gt;&lt;h3&gt;Work parallelism&lt;/h3&gt;&lt;p&gt;Different teams can work in parallel on each component, resulting in a faster final product delivery.&lt;/p&gt;&lt;h3&gt;Risk mitigation&lt;/h3&gt;&lt;p&gt;It&#39;s related to work parallelism. Problems on one work front do not affect other work fronts.&lt;/p&gt;&lt;h3&gt;Machinery costs&lt;/h3&gt;&lt;p&gt;The production of a part requires machines, that cost money. Delegating this production to other teams or companies avoids this cost.&lt;/p&gt;&lt;h3&gt;Specialization&lt;/h3&gt;&lt;p&gt;Teams and companies with specific knowledge of a type of component produce them with higher quality.&lt;/p&gt;&lt;h3&gt;Unit tests&lt;/h3&gt;&lt;p&gt;Interfaces enable isolated testing of a component, such that external dependencies are &lt;em&gt;&lt;strong&gt;mocked&lt;/strong&gt;&lt;/em&gt;, i.e., replaced with simulations or imitations. Because these are individualized tests, there is a higher level of attention and focus on the component itself, and it&#39;s not necessary for the entire system to be finished in order to test the component.&lt;/p&gt;&lt;p&gt;This also contributes to &lt;em&gt;&lt;strong&gt;shift-left testing&lt;/strong&gt;&lt;/em&gt;, which is the anticipation of quality assurance on the workflow — unit tests highlight problems earlier in the process.&lt;/p&gt;&lt;p&gt;&lt;picture class=my-4&gt;&lt;source alt=&quot;&quot; srcset=https://alexandrehtrb.github.io/assets/img/posts/2025_02_shift_left_testing.avif type=image/avif&gt;&lt;img alt=&quot;&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2025_02_shift_left_testing.jpg&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;em class=&quot;italic text-sm&quot;&gt;Comparison between shift-left and traditional testing approaches.&lt;/em&gt;&lt;/p&gt;&lt;h2 id=examples-of-interfaces-in-engineering tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/02/interfaces-as-a-principle-of-engineering/#examples-of-interfaces-in-engineering class=header-anchor&gt;&lt;span&gt;Examples of interfaces in engineering&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;h3&gt;Computers&lt;/h3&gt;&lt;p&gt;The hardware of a computer is extremely modular, making it easy to swap parts during repairs or upgrades.&lt;/p&gt;&lt;p&gt;&lt;picture class=my-4&gt;&lt;source alt=&quot;&quot; srcset=https://alexandrehtrb.github.io/assets/img/posts/2025_02_computer_motherboard_diagram.avif type=image/avif&gt;&lt;img alt=&quot;&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2025_02_computer_motherboard_diagram.jpg&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;em class=&quot;italic text-sm&quot;&gt;Diagram of a computer&#39;s motherboard.&lt;/em&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Any processor with the same socket as the motherboard can be used;&lt;/li&gt;&lt;li&gt;Any RAM memory stick with the same socket (e.g. DIMM, SO-DIMM) and the same class (e.g. DDR3, DDR4, DDR5) as the motherboard is accepted;&lt;/li&gt;&lt;li&gt;Any SATA device is accepted: hard drives, CD/DVD drives.&lt;/li&gt;&lt;li&gt;Any power supply can be used, as long as it provides power through the motherboard&#39;s corresponding connector (e.g. ATX);&lt;/li&gt;&lt;li&gt;And last but not least, a motherboard can be changed while keeping other parts.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Plumbing and electrical systems&lt;/h3&gt;&lt;img alt=&quot;Circuit breaker panel&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2025_02_circuit_breaker_panel.jpg class=my-4&gt;&lt;p&gt;Plumbing and electrical systems are also highly modularized.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Circuit breakers and valves enable subsytems to be isolated and repaired without affecting others.&lt;/li&gt;&lt;li&gt;Parts can be easily replaced.&lt;ul&gt;&lt;li&gt;For electrical: outlets, lamps, switches, circuit breakers; parts just need to comply with voltage and maximum current specifications.&lt;/li&gt;&lt;li&gt;For plumbing: siphons, faucets, shower heads; parts just need to comply with the plumbing diameter.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;The exception is repairs on conduits and pipes, usually located inside walls and under floors, but issues with those parts tend to be rarer.&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;h1 id=possible-drawbacks tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/02/interfaces-as-a-principle-of-engineering/#possible-drawbacks class=header-anchor&gt;&lt;span&gt;Possible drawbacks&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;h3&gt;Energy and material efficiency&lt;/h3&gt;&lt;p&gt;Connections consume energy and materials during construction and operation phases. In condensed or directly linked components, these losses are mitigated or even eliminated.&lt;/p&gt;&lt;h3&gt;System cohesion&lt;/h3&gt;&lt;p&gt;In every connection, there is the risk of component mismatch. Reducing the number of intermediaries makes the system more cohesive.&lt;/p&gt;&lt;h3&gt;Freedom of innovation&lt;/h3&gt;&lt;p&gt;Interfaces defined by third parties may not fulfill a use case in the best possible way. In these situations, it may be beneficial to deviate from existing standards and create your own interfaces.&lt;/p&gt;&lt;h2 id=case-study%3A-aviation-fuel-in-airports tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/02/interfaces-as-a-principle-of-engineering/#case-study%3A-aviation-fuel-in-airports class=header-anchor&gt;&lt;span&gt;Case study: Aviation fuel in airports&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Airports need aviation fuel (usually kerosene) to refill aircrafts&#39; tanks.&lt;/p&gt;&lt;p&gt;At small and medium-sized airports, kerosene is delivered by tanker trucks to storage tanks. At large airports with high fuel demand, however, kerosene is supplied via pipelines, directly from refineries.&lt;/p&gt;&lt;p&gt;These pipelines are expensive to build, but the high demand justifies their cost, and the operation is cheaper and more efficient than relying on tanker trucks.&lt;/p&gt;&lt;p&gt;During the 2018 Brazil truck drivers&#39; strike, airports that relied on tanker trucks suffered from fuel shortages and some of them had their operations paralysed. On the other hand, airports served by pipelines (Cumbica and Galeão) kept their operations as usual.&lt;/p&gt;&lt;img alt=&quot;Aviation fuel storage in Guarulhos airport&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2025_02_aviation_fuel_tanks.jpg class=my-4&gt;&lt;br&gt;&lt;h1 id=conclusion tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/02/interfaces-as-a-principle-of-engineering/#conclusion class=header-anchor&gt;&lt;span&gt;Conclusion&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;The concept of interfaces originates from the idea of interchangeable parts, and their use results in better, more reliable systems, that are cheaper, easier to maintain, and quicker to build. Moreover, interfaces contribute to the reuse of parts, preventing the need to replace entire systems.&lt;/p&gt;&lt;p&gt;In some cases, nevertheless, creating your own interfaces, or &quot;cutting out the middleman&quot;, can make your system more cohesive and efficient.&lt;/p&gt;&lt;br&gt;&lt;h1 id=sources-and-interesting-reads tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/02/interfaces-as-a-principle-of-engineering/#sources-and-interesting-reads class=header-anchor&gt;&lt;span&gt;Sources and interesting reads&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://mermaid.live&gt;Mermaid diagrams&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://en.wikipedia.org/wiki/Interchangeable_parts&gt;Wikipedia - Interchangeable parts&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://blog.onedaytesting.com.br/shift-left-testing/ &gt;One Day Testing Blog - Shift Left Testing: A prática de teste que antecipa problemas e acelera entregas&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://lightrun.com/shift-left-testing/ &gt;Lightrun - Shift Left Testing: 6 Essentials for Successful Implementation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://computer.howstuffworks.com/motherboard1.htm&gt;How Stuff Works - How Motherboards Work&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://en.wikipedia.org/wiki/2018_Brazil_truck_drivers%27_strike&gt;Wikipedia - 2018 Brazil truck drivers&#39; strike&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://g1.globo.com/economia/noticia/so-8-aeroportos-no-pais-estao-sendo-reabastecidos-regularmente-entre-eles-guarulhos-congonhas-galeao-e-santos-dumont.ghtml&gt;G1 - Só 8 aeroportos no país estão sendo reabastecidos regularmente, entre eles Guarulhos, Congonhas, Galeão e Santos Dumont (05/25/2018)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://www.cnt.org.br/agencia-cnt/saiba-como-funciona-abastecimento-maiores-aeroportos&gt;Confederação Nacional do Transporte - Saiba como funciona o abastecimento em dois dos maiores aeroportos do Brasil&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Introduction to FFmpeg</title>
    <link href="https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/" />
    <updated>2025-01-13T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/</id>
    <content type="html">&lt;h2 id=introduction tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#introduction class=header-anchor&gt;&lt;span&gt;Introduction&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Do you know that funny video on the Internet? Or the movie in the theatre? If you&#39;ve watched any digital video over the last 15 years, there&#39;s a good chance that FFmpeg was involved at some point, whether for editing, playback, or distribution.&lt;/p&gt;&lt;p&gt;FFmpeg is a video and audio transformation software that is used by multimedia companies like YouTube, TikTok, Vimeo, and many others.&lt;/p&gt;&lt;p&gt;In this article, we&#39;ll learn how to use it through practical examples.&lt;/p&gt;&lt;h2 id=index tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#index class=header-anchor&gt;&lt;span&gt;Index&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#ffmpeg-installation&gt;FFmpeg installation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#change-file-format&gt;Change file format&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#extract-audio-from-a-video&gt;Extract audio from a video&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#reduce-file-size&gt;Reduce file size&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#cut-part-of-a-video&gt;Cut part of a video&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#increase-and-decrease-audio-volume&gt;Increase and decrease audio volume&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#resize-frames&gt;Resize frames&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#insert-subtitles&gt;Insert subtitles&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#add-text-on-top-of-the-video&gt;Add text on top of the video&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#inspect-metadata&gt;Inspect metadata&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=ffmpeg-installation tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#ffmpeg-installation class=header-anchor&gt;&lt;span&gt;FFmpeg installation&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;h3&gt;Linux&lt;/h3&gt;&lt;p&gt;Debian / Ubuntu:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;sudo&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; apt&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; update&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;sudo&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; apt&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; install&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; ffmpeg&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ffmpeg&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -version&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Fedora:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;sudo&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; dnf&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; install&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;$(&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;rpm&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -E&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; %fedora&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;.noarch.rpm&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;sudo&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; dnf&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; install&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;$(&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;rpm&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -E&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; %fedora&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;.noarch.rpm&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;sudo&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; dnf&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; upgrade&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; --refresh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;sudo&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; dnf&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; install&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; ffmpeg&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; --allowerasing&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;sudo&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; dnf&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; install&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; ffmpeg-devel&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; --allowerasing&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ffmpeg&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -version&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Arch Linux:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;sudo&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; pacman&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -Sy&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;sudo&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; pacman&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -S&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; ffmpeg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ffmpeg&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -version&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;macOS&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Install &lt;a href=https://brew.sh/ &gt;Brew&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Execute on Terminal:&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;brew&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; update&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;brew&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; install&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; ffmpeg&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ffmpeg&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -version&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Windows&lt;/h3&gt;&lt;p&gt;You can install via Winget (available for Windows 11, Windows Server 2025):&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;winget install &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;--&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;id&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;Gyan.FFmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;e&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or install manually:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Download the latest FFMpeg for Windows release (&lt;a href=https://github.com/GyanD/codexffmpeg/releases&gt;link&lt;/a&gt;). The &lt;code&gt;essentials&lt;/code&gt; version is the most appropriate for most users.&lt;/li&gt;&lt;li&gt;Unzip the file.&lt;/li&gt;&lt;li&gt;Add the &lt;code&gt;bin&lt;/code&gt; folder to PATH. For that:&lt;ul&gt;&lt;li&gt;On Windows Explorer, mouse right-click on &lt;em&gt;This Computer&lt;/em&gt; &gt; &lt;em&gt;Properties&lt;/em&gt;.&lt;/li&gt;&lt;li&gt;On the next window, click on &lt;em&gt;Advanced system configurations&lt;/em&gt;.&lt;/li&gt;&lt;li&gt;On &lt;em&gt;System Properties&lt;/em&gt;, click on &lt;em&gt;Environment Variables...&lt;/em&gt;.&lt;/li&gt;&lt;li&gt;On &lt;em&gt;User Variables for X&lt;/em&gt;, select the line with &lt;strong&gt;Path&lt;/strong&gt; and click on &lt;em&gt;Edit...&lt;/em&gt;.&lt;/li&gt;&lt;li&gt;Add the bin folder path to the list. It will be something like: &lt;code&gt;C:&#92;Users&#92;user&#92;Downloads&#92;ffmpeg-7.0.1-essentials_build&#92;bin&lt;/code&gt; (change for the path in your machine).&lt;/li&gt;&lt;li&gt;Click OK on the windows to save the changes.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;How to use&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;FFmpeg is used via Terminal, Command Prompt, or PowerShell. In your computer, open one of those programs.&lt;/li&gt;&lt;li&gt;In the examples below, the file paths are specified without their folders, which implies the current folder in the command line. To change the current directory:&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;cd C:&#92;Users&#92;user&#92;Videos&#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the files are (or will be generated) in other folders, the full file path is required:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;C:&#92;Videos&#92;input.mov&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c copy &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;C:&#92;Videos&#92;output.mp4&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;h1 id=operations tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#operations class=header-anchor&gt;&lt;span&gt;Operations&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;h2 id=change-file-format tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#change-file-format class=header-anchor&gt;&lt;span&gt;Change file format&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Video file formats usually are just transport containers, whereas their content is determined by the codecs. Some video formats: &lt;code&gt;MP4&lt;/code&gt;, &lt;code&gt;AVI&lt;/code&gt;, &lt;code&gt;MKV&lt;/code&gt;, &lt;code&gt;MOV&lt;/code&gt;, &lt;code&gt;WebM&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;The most popular video codecs are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;H.264&lt;/strong&gt;, it&#39;s one of the oldest and is widely supported.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;H.265&lt;/strong&gt;, more recent and has up to 50% smaller file sizes than H.264. However, some browsers and players do not support it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;AV1&lt;/strong&gt; is a newer codec. It has a royalty-free license and promises better compression than H.265, but FFmpeg doesn&#39;t support it very well yet (01/06/2025).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;VP9&lt;/strong&gt;, used by YouTube and in &lt;code&gt;.webm&lt;/code&gt; videos.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The main audio codecs are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;MP3&lt;/strong&gt;, widely supported, lossy, good compression, good quality.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;AAC&lt;/strong&gt;, used in MP4, compression and quality a bit better than MP3.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Opus&lt;/strong&gt;, lossy with good quality.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;FLAC&lt;/strong&gt;, lossless, but with compression.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;File conversion keeping the codecs:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mov &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c copy output.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;File and codec conversion (transcoding):&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;-c:v&lt;/code&gt;: video codec&lt;/li&gt;&lt;li&gt;&lt;code&gt;-c:a&lt;/code&gt;: audio codec&lt;/li&gt;&lt;li&gt;&lt;code&gt;-b:a&lt;/code&gt;: audio bitrate&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mov &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:v h264 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:a libopus &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;b:a 96k output.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=extract-audio-from-a-video tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#extract-audio-from-a-video class=header-anchor&gt;&lt;span&gt;Extract audio from a video&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Full extraction, keeping the codec:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;MP4 -&gt; AAC or M4A&lt;/li&gt;&lt;li&gt;MKV -&gt; many codecs&lt;/li&gt;&lt;li&gt;WebM -&gt; Opus or Ogg Vorbis&lt;/li&gt;&lt;li&gt;MOV -&gt; ALAC&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;vn &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:a copy output.m4a&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Extraction with transcoding. &lt;code&gt;-q:a&lt;/code&gt; is the quality, from 0 to 9; lower means better.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;vn &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:a libmp3lame &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;q:a &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; output.mp3&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Audio extraction from part of the video. &lt;code&gt;-ss&lt;/code&gt; is the beginning, &lt;code&gt;-to&lt;/code&gt; is the end.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ss &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;00&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;00&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;07&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;to &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;00&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;00&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;10.7&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;vn &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:a libmp3lame &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;q:a &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; output.mp3&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=reduce-file-size tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#reduce-file-size class=header-anchor&gt;&lt;span&gt;Reduce file size&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;There are many ways to reduce the file size of a video. In this section, we&#39;ll cover compression.&lt;/p&gt;&lt;p&gt;To fully understand how it works, I recommend reading the codec official docs (such as: &lt;a href=https://trac.ffmpeg.org/wiki/Encode/H.264&gt;H.264&lt;/a&gt; and &lt;a href=https://trac.ffmpeg.org/wiki/Encode/H.265&gt;H.265&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Limit with CRF.&lt;/strong&gt; The &lt;code&gt;-crf&lt;/code&gt; flag, &lt;em&gt;Constant Rate Factor&lt;/em&gt;, controls quality. Lower value means less compression and higher quality. The scale goes from 0 to 51, default value is 23.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:v libx264 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;crf &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;23&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;pix_fmt yuv420p &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:a copy output.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;-pix_fmt yuv420p&lt;/code&gt; is necessary for compatibility with Apple QuickTime and some other players.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;Limit bitrate.&lt;/strong&gt; You can limit the bitrate, making the file size more predictable. This option can be combined with CRF. In the example below, the encoder aims to limit the maximum bitrate in 1Mbit/s.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:v libx264 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;crf &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;23&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;maxrate &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1M&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;bufsize &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2M&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;pix_fmt yuv420p &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:a copy output.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Transcode to more modern codecs.&lt;/strong&gt; H.265, for example, generates lower files sizes than H.264. CRF scale goes from 0 to 51, default value is 28.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Keep in mind that not every player and browser supports H.265.&lt;/em&gt;&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:v libx265 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;crf &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;28&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;tag:v hvc1 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:a copy output.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;-tag:v hvc1&lt;/code&gt; is for compatibility with Apple QuickTime.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2 id=cut-part-of-a-video tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#cut-part-of-a-video class=header-anchor&gt;&lt;span&gt;Cut part of a video&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ss &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;00&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;00&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;19.4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;to &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;00&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;03&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;50&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c copy output.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The time parameters can be placed before or after the input parameter.&lt;/p&gt;&lt;p&gt;When placed before (&lt;code&gt;-ss -to -i&lt;/code&gt;), the operation is faster because the cut is made on the input, which is processed afterwards; however, the cut may be imprecise, and there may dyssynchrony between audio and video.&lt;/p&gt;&lt;p&gt;When placed after (&lt;code&gt;-i -ss -to&lt;/code&gt;), the cut is more precise and there is no risk of dyssynchrony, but the operation is slower because the cut is made on the output, after the video is processed.&lt;/p&gt;&lt;p&gt;When in doubt, you can first try the input cut (first option) and check the result. If the result is not good, then try the output cut (second option).&lt;/p&gt;&lt;h2 id=increase-and-decrease-audio-volume tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#increase-and-decrease-audio-volume class=header-anchor&gt;&lt;span&gt;Increase and decrease audio volume&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The example below increases the audio volume by 2.4 times.&lt;/p&gt;&lt;p&gt;To reduce it by half, use 0.5.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;af &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;volume=2.4&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; output.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=resize-frames tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#resize-frames class=header-anchor&gt;&lt;span&gt;Resize frames&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Fixed dimensions, width x height:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;lavfi &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;scale=&#39;720:480&#39;&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; output.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;One fixed dimension and the other proportional, to maintain the aspect ratio:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;lavfi &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;scale=&#39;720:-2&#39;&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; output.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Proportional reduction:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;lavfi &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;scale=&#39;floor(iw/4)*2:floor(ih/4)*2&#39;&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; output.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the example above, the function &lt;code&gt;floor(d/4) * 2&lt;/code&gt; was used to calculate half, because some codecs require dimensions to always be even numbers (divisible by 2).&lt;/p&gt;&lt;h2 id=insert-subtitles tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#insert-subtitles class=header-anchor&gt;&lt;span&gt;Insert subtitles&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;h3&gt;Optional subtitles&lt;/h3&gt;&lt;p&gt;Also known as soft subtitles, they are visible on the player with mouse right-click and selecting the subtitle.&lt;/p&gt;&lt;p&gt;More than one subtitle can be added, for example, for more than one language.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i subtitles.srt &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c copy &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:s mov_text &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;metadata:s:s:&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;0&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; language&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;eng output.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Burned subtitles&lt;/h3&gt;&lt;p&gt;Hard or burned subtitles are imprinted over the video.&lt;/p&gt;&lt;p&gt;&lt;code&gt;subtitles.srt&lt;/code&gt; is the subtitles file. &lt;code&gt;Alignment=2&lt;/code&gt; means bottom center position.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;lavfi &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;subtitles=subtitles.srt:force_style=&#39;Alignment=2,OutlineColour=&amp;H100000000,BorderStyle=3,Outline=1,Shadow=0,Fontsize=18,MarginL=5,MarginV=25&#39;&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;crf &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:a copy output.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Example of result:&lt;/p&gt;&lt;p&gt;&lt;video controls src=https://alexandrehtrb.github.io/assets/videos/posts/2025_01_ffmpeg_burned_subtitles.mp4&gt;&lt;/video&gt;&lt;/p&gt;&lt;h2 id=add-text-on-top-of-the-video tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#add-text-on-top-of-the-video class=header-anchor&gt;&lt;span&gt;Add text on top of the video&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;We will use &lt;code&gt;pad&lt;/code&gt; and &lt;code&gt;drawtext&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;code&gt;pad&lt;/code&gt; adds a layer around the video; in the example below, we&#39;ll make it black above the video. For that, we&#39;ll extend the frame height by 100 pixels and draw the layer between 0 and 100 on the vertical direction:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;# ih = input height&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;pad=width=iw:height=(ih+100):x=0:y=100:color=black&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;drawtext&lt;/code&gt; renders the text on the layer. Our text will have two lines, so we&#39;ll use it twice.&lt;/p&gt;&lt;p&gt;&lt;code&gt;x=(w-text_w)/2&lt;/code&gt; centers the text horizontally. The &lt;code&gt;y&lt;/code&gt; coordinate determines the line&#39;s vertical position.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;drawtext=:font=&#39;Arial&#39;:text=&#39;Men′s Volleyball 2016 Olympics&#39;:fontsize=24:fontcolor=white:x=(w-text_w)/2:y=25&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;drawtext=:font=&#39;Arial&#39;:text=&#39;BRA 3 - 0 ITA&#39;:fontsize=24:fontcolor=white:x=(w-text_w)/2:y=54&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Command:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffmpeg &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;i input.mp4 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;lavfi &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;format=yuv420p,pad=width=iw:height=(ih+100):x=0:y=100:color=black, drawtext=:font=&#39;Arial&#39;:text=&#39;Men′s Volleyball 2016 Olympics&#39;:fontsize=24:fontcolor=white:x=(w-text_w)/2:y=25, drawtext=:font=&#39;Arial&#39;:text=&#39;BRA 3 - 0 ITA&#39;:fontsize=24:fontcolor=white:x=(w-text_w)/2:y=54&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;c:v libx264 &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;crf &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;25&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; output.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;format=yuv420p&lt;/code&gt; is necessary for compatibility with Apple QuickTime and some other players.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Example of result:&lt;/p&gt;&lt;p&gt;&lt;video controls src=https://alexandrehtrb.github.io/assets/videos/posts/2025_01_ffmpeg_text_layer_on_top.mp4&gt;&lt;/video&gt;&lt;/p&gt;&lt;h2 id=inspect-metadata tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#inspect-metadata class=header-anchor&gt;&lt;span&gt;Inspect metadata&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Details which codecs were used; video and audio resolution and bitrate; and other information.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ffprobe video.mp4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;h1 id=sources-and-interesting-reads tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2025/01/introduction-to-ffmpeg/#sources-and-interesting-reads class=header-anchor&gt;&lt;span&gt;Sources and interesting reads&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Oz8TYyn-k40&quot;&gt;007 GoldenEye - Bond and Xenia at the casino&lt;/a&gt; (all rights reserved)&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=KLIa2UaE2KE&quot;&gt;Rio 2016 Olympics - Brazil wins gold medal match for men&#39;s volleyball&lt;/a&gt; (all rights reserved)&lt;/li&gt;&lt;li&gt;&lt;a href=https://ffmpeg.org/ &gt;FFmpeg official site&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://trac.ffmpeg.org/wiki/Projects&gt;FFmpeg - Projects that use it&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://streaminglearningcenter.com/blogs/youtube-uses-ffmpeg-for-encoding.html&gt;Streaming Learning Center - YouTube uses FFmpeg for encoding&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://theirstack.com/en/technology/ffmpeg&gt;TheirStack - List of companies using FFmpeg&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://trac.ffmpeg.org/wiki/Encode/H.264&gt;FFmpeg - H.264 Video Encoding Guide&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://trac.ffmpeg.org/wiki/Encode/H.265&gt;FFmpeg - H.265/HEVC Video Encoding Guide&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://unix.stackexchange.com/questions/28803/how-can-i-reduce-a-videos-size-with-ffmpeg&gt;Unix Stack Exchange - How can I reduce a video&#39;s size with ffmpeg?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://trac.ffmpeg.org/wiki/Scaling&gt;FFmpeg - Scaling&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://trac.ffmpeg.org/wiki/Seeking&gt;FFmpeg - Seeking&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://stackoverflow.com/questions/6984628/ffmpeg-ss-weird-behaviour&gt;Stack Overflow - FFmpeg -ss weird behaviour&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://superuser.com/questions/624563/how-to-resize-a-video-to-make-it-smaller-with-ffmpeg&gt;Super User - How to resize a video to make it smaller with FFmpeg&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://www.whathifi.com/advice/mp3-aac-wav-flac-all-the-audio-file-formats-explained&gt;What Hi-Fi? - MP3, AAC, WAV, FLAC: all the audio file formats explained&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://stackoverflow.com/questions/57869367/ffmpeg-subtitles-alignment-and-position&gt;Stack Overflow - ffmpeg subtitles alignment and position&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://subtitletools.com/subtitle-sync-shifter&gt;Subtitle Tools - Sync subtitles&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;script&gt;document.querySelectorAll(&quot;pre.shiki&quot;).forEach(e=&gt;{e.classList.add(&quot;wrapped&quot;)})&lt;/script&gt;</content>
  </entry>
  <entry>
    <title>Special properties in .NET projects</title>
    <link href="https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/" />
    <updated>2024-12-17T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/</id>
    <content type="html">&lt;h1 id=.net-project-files tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#.net-project-files class=header-anchor&gt;&lt;span&gt;.NET project files&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;Certain configurations in .NET project files modify how a project is compiled, and the performance and size of published apps.&lt;/p&gt;&lt;p&gt;These configurations reside in .csproj (C#), .fsproj (F#) and .vbproj (VB.NET) files; they can also be passed via command-line arguments, when running &lt;code&gt;dotnet run&lt;/code&gt;, &lt;code&gt;dotnet build&lt;/code&gt; and &lt;code&gt;dotnet publish&lt;/code&gt;.&lt;/p&gt;&lt;h2 id=in-project-files tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#in-project-files class=header-anchor&gt;&lt;span&gt;In project files&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;Project&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; Sdk&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;Microsoft.NET.Sdk&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;    &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;OutputType&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;Exe&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;OutputType&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;    &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;TargetFramework&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;net8.0&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;TargetFramework&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;    &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;Nullable&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;enable&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;Nullable&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;    &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;ImplicitUsings&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;enable&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;ImplicitUsings&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;Project&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=via-command-line-arguments tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#via-command-line-arguments class=header-anchor&gt;&lt;span&gt;Via command-line arguments&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;dotnet publish &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;  --&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;configuration Release &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;  --&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;self&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;contained true &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;  --&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;runtime &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;linux-x64&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;  -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;p:PublishSingleFile&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;true &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;  --&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;output &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;./out/&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;h1 id=properties tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#properties class=header-anchor&gt;&lt;span&gt;Properties&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#targetframework&gt;TargetFramework&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#nullable&gt;Nullable&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#implicitusings&gt;ImplicitUsings&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#treatwarningsaserrors&gt;TreatWarningsAsErrors&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#configuration&gt;Configuration&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#selfcontained&gt;SelfContained&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#publishsinglefile&gt;PublishSingleFile&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#enablecompressioninsinglefile&gt;EnableCompressionInSingleFile&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#publishreadytorun&gt;PublishReadyToRun&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#trimming&gt;Trimming&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#nativeaot&gt;NativeAOT&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#version&gt;Version&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#applicationicon&gt;ApplicationIcon&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=targetframework tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#targetframework class=header-anchor&gt;&lt;span&gt;TargetFramework&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Specifies which .NET versions your project should compile against. Usually, only one TFM (&lt;em&gt;target framework moniker&lt;/em&gt;) is specified, but, if your project needs to support multiple .NET versions, you can specify a list of TFMs, separated by semi-colon (&#39;;&#39;).&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  &amp;lt;!-- only one --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;TargetFramework&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;net8.0&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;TargetFramework&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  &amp;lt;!-- multiple. plural used. --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;TargetFrameworks&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;netstandard1.4;net40;net45&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;TargetFrameworks&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=nullable tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#nullable class=header-anchor&gt;&lt;span&gt;Nullable&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;When present with the value true, warns whenever a variable that can be null is used in a place that doesn&#39;t accept null.&lt;/p&gt;&lt;p&gt;Consider the code below. There is a warning that a null value may be passed to the &lt;code&gt;int.Parse()&lt;/code&gt; method, which does not accept null strings.&lt;/p&gt;&lt;img alt=&quot;Possible null value warning&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2024_12_nullable_warning.png&gt;&lt;p&gt;There are four ways to solve this warning:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Modify the method signature. When a variable has a question mark after its type (&lt;code&gt;string?&lt;/code&gt;), it means that it accepts null values; abscence of question mark (&lt;code&gt;string&lt;/code&gt;) means only non-null values are accepted.&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; int&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; ConvertToInt&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; numericString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    int&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Parse&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;numericString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=2&gt;&lt;li&gt;Protect your code against null values.&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; int&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; ConvertToInt&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;? &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;numericString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;    if&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;numericString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; ==&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; null&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;        throw&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; new&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; ArgumentNullException&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;nameof&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;numericString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;        return&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; int&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Parse&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;numericString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=3&gt;&lt;li&gt;Apply an exclamation mark. It indicates that the value is safe.&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; int&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; ConvertToInt&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;? &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;numericString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    int&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Parse&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;numericString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;!&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=4&gt;&lt;li&gt;Disable nullable verification via preprocessor directive.&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E6C92&gt;#nullable disable warnings&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; int&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; ConvertToInt&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;? &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;numericString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        int&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Parse&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;numericString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E6C92&gt;#nullable restore warnings&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=implicitusings tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#implicitusings class=header-anchor&gt;&lt;span&gt;ImplicitUsings&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Implicitly adds to all code files (.cs, .fs, .vb) some commonly used namespaces, so they don&#39;t need to be declared.&lt;/p&gt;&lt;p&gt;The list of namespaces varies according to the project type.&lt;/p&gt;&lt;p&gt;For console apps and class libraries:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; System&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; System&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Collections&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Generic&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; System&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;IO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; System&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Linq&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; System&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Net&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Http&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; System&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Threading&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; System&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Threading&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Tasks&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For Web projects, the ones above, plus:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; System&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Net&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Http&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Json&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;AspNetCore&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Builder&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;AspNetCore&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Hosting&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;AspNetCore&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Http&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;AspNetCore&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Routing&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Extensions&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Configuration&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Extensions&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;DependencyInjection&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Extensions&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Hosting&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Extensions&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Logging&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For Workers, the first list, and:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Extensions&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Configuration&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Extensions&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;DependencyInjection&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Extensions&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Hosting&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Extensions&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Logging&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=treatwarningsaserrors tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#treatwarningsaserrors class=header-anchor&gt;&lt;span&gt;TreatWarningsAsErrors&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;If there are any warnings in the project, the compilation will fail.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;TreatWarningsAsErrors&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;True&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;TreatWarningsAsErrors&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is an interesting option to improve code quality, as it forces developers to pay attention to warnings, which indicate possible weaknesses and problems. An example is combining this option with &lt;em&gt;Nullable&lt;/em&gt;.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Author&#39;s comment&lt;/strong&gt;: this alone will not make your code better. The warnings can be circumvented, through &lt;code&gt;#pragma warning disable&lt;/code&gt; or by ignoring nullability checks with exclamation marks (see above). A good quality code results from good programming practices and peer revisions.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2 id=configuration tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#configuration class=header-anchor&gt;&lt;span&gt;Configuration&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Determines the compilation mode, Debug or Release.&lt;/p&gt;&lt;p&gt;In Debug mode, the compilation produces symbol files (.pdb) that are used by the IDE for debugging and to set breakpoints. Also, the code is not optimized by the compiler.&lt;/p&gt;&lt;p&gt;In Release mode, the compilation applies optimizations to the code and no symbol files are produced. When a program is compiled for deployment, Release config should be used.&lt;/p&gt;&lt;p&gt;This option is passed by flags.&lt;/p&gt;&lt;h2 id=selfcontained tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#selfcontained class=header-anchor&gt;&lt;span&gt;SelfContained&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Embeds the .NET runtime in the published app. This means that the target machine (where the app will run) won&#39;t need to have it installed.&lt;/p&gt;&lt;p&gt;This option increases the app size (for having the .NET runtime inside).&lt;/p&gt;&lt;h2 id=publishsinglefile tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#publishsinglefile class=header-anchor&gt;&lt;span&gt;PublishSingleFile&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Condenses the program and its DLLs into a single executable file, reducing the number of published files. This is interesting for portable programs.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Interop DLLs in C/C++ are unaffected by this option and will appear in separate files.&lt;/em&gt;&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PublishSingleFile&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;True&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PublishSingleFile&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=enablecompressioninsinglefile tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#enablecompressioninsinglefile class=header-anchor&gt;&lt;span&gt;EnableCompressionInSingleFile&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;When used with the option above, compresses the condensed executable file, decreasing its size.&lt;/p&gt;&lt;p&gt;A side-effect is it makes the program initialization slower, because the content needs to be extracted before execution. (The extraction is in memory; no files are created.)&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;EnableCompressionInSingleFile&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;True&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;EnableCompressionInSingleFile&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=publishreadytorun tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#publishreadytorun class=header-anchor&gt;&lt;span&gt;PublishReadyToRun&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;This is a special compiler optimization that makes the program startup faster, predicting how it will run in the target machine and replacing parts of intermediary code (IL, intermediate language) with native machine code. This is interesting for APIs, because they take less time to become operational.&lt;/p&gt;&lt;p&gt;This option increases the app size and the compilation takes a longer time (when publishing).&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PublishReadyToRun&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;True&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PublishReadyToRun&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=trimming tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#trimming class=header-anchor&gt;&lt;span&gt;Trimming&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Trims away unused parts of the code and of inner dependencies, greatly reducing the size of the published app.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;This option must be used carefully&lt;/strong&gt;, because it may remove important parts of the code and cause errors during execution. To avoid these problems, the compiler emits warnings on lines susceptible to removal, for the developer to find alternatives or mark the code to not be removed.&lt;/p&gt;&lt;p&gt;The trimming may be partial, only on specified assemblies; or full, over the entire app.&lt;/p&gt;&lt;p&gt;This is an extensive subject and requires a thorough read, so I recommend checking the &lt;a href=https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options&gt;docs&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Example of partial trimming:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PublishTrimmed&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;true&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PublishTrimmed&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;TrimMode&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;partial&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;TrimMode&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;&amp;lt;!-- list of assemblies that will be trimmed --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;ItemGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;TrimmableAssembly&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; Include&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;MyAssembly&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;ItemGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=nativeaot tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#nativeaot class=header-anchor&gt;&lt;span&gt;NativeAOT&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;NativeAOT is a special type of compilation straight to native machine code, improving app performance.&lt;/p&gt;&lt;p&gt;In traditional compilation, the final executable is composed of intermediate language code (IL) that is interpreted by the .NET runtime (CoreCLR). During execution, the runtime translates each IL instruction into native machine code, and that&#39;s how the program runs.&lt;/p&gt;&lt;p&gt;In NativeAOT compilation, the runtime is no longer needed and many processor architecture and operating system optimizations can be applied, causing:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;faster execution,&lt;/li&gt;&lt;li&gt;less memory usage,&lt;/li&gt;&lt;li&gt;and lower app size.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;This compilation option is not so easy to use, though.&lt;/strong&gt; It requires that all code paths can be statically analysed, in other words, &lt;em&gt;reflection cannot be used in the code&lt;/em&gt;, which affects for example JSON and XML (de)serialization.&lt;/p&gt;&lt;p&gt;For JSON (de)serialization, a solution is System.Text.Json source generators, that write and read JSONs through compile-time generated code.&lt;/p&gt;&lt;p&gt;WPF and Windows Forms are heavily reflection-based and because of that they don&#39;t support NativeAOT. However, console and ASP.NET minimal APIs do have support for NativeAOT.&lt;/p&gt;&lt;p&gt;Just like trimming, using this feature requires caution and the &lt;a href=https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/ &gt;official docs&lt;/a&gt; should be read.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PublishAot&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;true&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PublishAot&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=version tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#version class=header-anchor&gt;&lt;span&gt;Version&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Sets the application, assembly or file version.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;Version&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;3.7.1&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;Version&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  &amp;lt;!-- Version value is reused below --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;FileVersion&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;$(Version)&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;FileVersion&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;AssemblyVersion&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;$(Version)&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;AssemblyVersion&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To retrieve the version by code:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; versionName&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; Assembly&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;GetExecutingAssembly&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;                             .&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;GetName&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;                             .&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Version&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;?&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;                             .&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ToString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// versionName = &quot;3.7.1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: the versioning of NuGet packages is done through other properties. Read more in the &lt;a href=https://learn.microsoft.com/en-us/nuget/create-packages/package-authoring-best-practices&gt;docs&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2 id=applicationicon tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#applicationicon class=header-anchor&gt;&lt;span&gt;ApplicationIcon&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Sets an icon on the program for Windows Explorer.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;ApplicationIcon&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;my_program.ico&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;ApplicationIcon&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;PropertyGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=sources-and-interesting-reads tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/12/special-properties-in-dotnet-projects/#sources-and-interesting-reads class=header-anchor&gt;&lt;span&gt;Sources and interesting reads&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/dotnet/standard/frameworks#how-to-specify-a-target-framework&gt;.NET Docs - Target frameworks in SDK-style projects&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://devblogs.microsoft.com/dotnet/embracing-nullable-reference-types/ &gt;Microsoft DevBlogs - Embracing nullable reference types&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://dotnetcoretutorials.com/implicit-using-statements-in-net-6/ &gt;DotNetCore Tutorials - Implicit Using Statements In .NET 6&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/dotnet/core/deploying/single-file/overview&gt;.NET Docs - Single-file deployment&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/dotnet/core/deploying/ &gt;.NET Docs - .NET application publishing overview&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/dotnet/core/deploying/ready-to-run&gt;.NET Docs - ReadyToRun Compilation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options&gt;.NET Docs - Trimming options&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/ &gt;.NET Docs - Native AOT deployment&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation&gt;.NET Docs - How to use source generation in System.Text.Json&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://github.com/dotnet/core/issues/6260&gt;GitHub Dotnet Core repo - How to set application icon on Windows?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/nuget/create-packages/package-authoring-best-practices&gt;.NET Docs - NuGet Package authoring best practices&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props&gt;.NET Docs - MSBuild reference for .NET SDK projects&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-properties?view=vs-2022&quot;&gt;MSBuild Docs - Common MSBuild project properties&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-reserved-and-well-known-properties?view=vs-2022&quot;&gt;MSBuild Docs - MSBuild reserved and well-known properties&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>The fathers of quality, Deming and Shewhart</title>
    <link href="https://alexandrehtrb.github.io/posts/2024/10/the-fathers-of-quality-deming-and-shewhart/" />
    <updated>2024-10-14T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2024/10/the-fathers-of-quality-deming-and-shewhart/</id>
    <content type="html">&lt;p&gt;In the 1980s, there was a prevailing thought in popular culture that Japan would take over the world — not by force, but by its vigorous economy, which was the second largest in the world between 1990 and 2010. We can see this in many movies, such as &lt;em&gt;Back To The Future Part II&lt;/em&gt;, where Marty McFly has a Japanese boss in the future; and in &lt;em&gt;Die Hard&lt;/em&gt;, where John McClane&#39;s wife works for a Japanese company. Her boss is Mr. Takagi, in the picture below.&lt;/p&gt;&lt;p&gt;&lt;picture class=my-4&gt;&lt;source alt=&quot;Die Hard - John McClane, Ellis, Takagi and Holly Gennaro&quot; srcset=https://alexandrehtrb.github.io/assets/img/posts/2024_10_die_hard_takagi.avif type=image/avif&gt;&lt;img alt=&quot;Die Hard - John McClane, Ellis, Takagi and Holly Gennaro&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_10_die_hard_takagi.jpg&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;The keyword that summarizes the Japanese economic miracle is &lt;strong&gt;quality&lt;/strong&gt;. By focusing on better products, with fewer defects and more efficient processes, their industry gained the attention of consumers and space in the global economy.&lt;/p&gt;&lt;p&gt;This transformation began with two men, whose works changed Japan and companies around the whole world.&lt;/p&gt;&lt;h2 id=deming-and-shewhart tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/10/the-fathers-of-quality-deming-and-shewhart/#deming-and-shewhart class=header-anchor&gt;&lt;span&gt;Deming and Shewhart&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;William Edwards Deming (1900-1993) was an American statistician, engineer, economist and consultant. For his work, he is known as &lt;em&gt;the father of quality&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Deming graduated in electrical engineering and later specialized in mathematical physics. In 1927, he started working in the United States Department of Agriculture, and there, through colleagues, he met Walter Andrew Shewhart (1891-1967), who is known as &lt;em&gt;the father of statistical quality control&lt;/em&gt;. Shewhart was an engineer of Bell Telephone Company and used statistics to improve the reliability and voice clarity of telephone lines.&lt;/p&gt;&lt;p&gt;Shewhart taught Deming many tools that served as the basis for his future works, among them, control charts and PDCA cycles.&lt;/p&gt;&lt;h3&gt;Control chart&lt;/h3&gt;&lt;p&gt;Shows how much something stays within a margin of tolerance over time.&lt;/p&gt;&lt;p&gt;Some real-life examples: the size of produced mechanical parts; the amount of active ingredient in each tablet; the travel time between two cities.&lt;/p&gt;&lt;p&gt;Below, we see a process that is initially out of control; later, it stays within the tolerance zone; and finally, within a tighter zone, indicating an improvement on the quality of the process.&lt;/p&gt;&lt;img alt=&quot;Control chart&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_10_control_chart.jpg class=my-4&gt;&lt;p&gt;With a control chart we can detect anomalies in a production line, or estimate when a machine will need maintenance.&lt;/p&gt;&lt;h2 id=second-world-war-and-post-war tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/10/the-fathers-of-quality-deming-and-shewhart/#second-world-war-and-post-war class=header-anchor&gt;&lt;span&gt;Second World War and post-war&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;During World War II, Deming was part of the U.S. Emergency Technical Committee, focused on improving the wartime production. Statistical quality control was used on factories and reduced the number of failures in American weaponry.&lt;/p&gt;&lt;p&gt;After the war, Deming was convoked to prepare the 1951 Japanese census and his effort and involvement in Japanese society caught attention, to the point that the Japanese Union of Scientists and Engineers (JUSE) invited him to teach them about statistics and quality. His lessons were a tremendous success and were transcribed into books with thousands of copies sold.&lt;/p&gt;&lt;p&gt;In a lecture to Japanese executives in 1950, Deming told them that implementing statistical quality control on their companies would lower costs and waste, increase productivity and attract consumers, allured by better products. The executives applied these ideas into their businesses and had very positive results.&lt;/p&gt;&lt;p&gt;In the following decades, Japan witnessed its economy rise from the ashes and become one of the largest in the world, largely due to the implementation of Deming&#39;s ideas. The GDP growth was around 8-10% yearly.&lt;/p&gt;&lt;img alt=&quot;William Edwards Deming in Japan&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_10_william_edwards_deming_in_japan.jpg class=my-4&gt; &lt;em class=&quot;italic text-sm&quot;&gt;Deming, at the right, visiting Japan.&lt;/em&gt;&lt;h3&gt;Case study: Mazda-Ford transmissions&lt;/h3&gt;&lt;p&gt;In the 80s, Ford partnered with Mazda to produce automatic transmissions for Ford automobiles.&lt;/p&gt;&lt;p&gt;Both companies produced this transmission and in both of them the products had full specification conformance. Despite that, Ford transmissions had a higher number of customer complaints and incurred higher repair costs; not just that, customers came over to Ford dealerships asking for their new cars to have Japanese transmissions, because they had a smoother driving experience.&lt;/p&gt;&lt;p&gt;Ford engineers investigated and noted that Ford transmissions had a variance of 70% within the margin of tolerance, while Mazda transmissions had a variance of 27%. For example, if the specification of a part was 300mm ± 3mm, Ford&#39;s parts size varied by 2.1mm; while Mazda&#39;s varied by 1.15mm.&lt;/p&gt;&lt;p&gt;Mazda&#39;s production cost was slightly more expensive, but compensated by having less warranty claims.&lt;/p&gt;&lt;p&gt;After this study, the Ford factory improved the quality of its transmissions, that became better than Mazda&#39;s.&lt;/p&gt;&lt;h3&gt;Case study: Sony TVs&lt;/h3&gt;&lt;p&gt;Also in the 1980s, Sony had two TV production plants, one in Japan and one in San Diego, California.&lt;/p&gt;&lt;p&gt;One of the quality factors for a TV was the colour density, with a margin of tolerance between 9 and 14. TVs made in San Diego all were within tolerance, while 1.3 for every 1000 of the ones made in Japan were out. Regardless of that, consumers preferred Japanese TVs, because the image on the screen was more homogenous and with a better resolution, due to a lower variance of colour density.&lt;/p&gt;&lt;h2 id=recognition-in-the-u.s. tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/10/the-fathers-of-quality-deming-and-shewhart/#recognition-in-the-u.s. class=header-anchor&gt;&lt;span&gt;Recognition in the U.S.&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Ironically, Deming&#39;s ideas fell into disuse in the United States after the war and were not widely accepted by American executives, who believed that quality was a cost, rather than an investment.&lt;/p&gt;&lt;p&gt;In the following decades, Deming extended his work for beyond statistics and addressed how to improve the efficiency and organization of companies, summarizing his ideas in &lt;strong&gt;14 points for management&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;In 1980, NBC aired a documentary comparing American and Japanese companies. Deming was interviewed in this documentary, and after his appearance on TV, many corporations requested Deming&#39;s consultancy services. One of the companies that hired him was Ford.&lt;/p&gt;&lt;p&gt;At the beginning of the 1980s, Ford was facing a major crisis, with losses exceeding $3 billion. Deming was called and said that the management was responsible for 85% of the problems in developing better cars. Ford executives took this seriously and adopted Deming&#39;s ideas: by 1986, Ford became the most profitable American auto company, surpassing General Motors for the first time since the 1920s. Revenue grew consistently over the following years.&lt;/p&gt;&lt;img alt=&quot;Ford Taurus assembly line, in 1986&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_10_ford_taurus_production_line.jpg class=my-4&gt; &lt;em class=&quot;italic text-sm&quot;&gt;The Ford Taurus assembly line in 1986. The car was a major success and saved the company from bankruptcy.&lt;/em&gt;&lt;h2 id=14-points-for-management tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/10/the-fathers-of-quality-deming-and-shewhart/#14-points-for-management class=header-anchor&gt;&lt;span&gt;14 points for management&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;In his book &lt;em&gt;Out of the Crisis&lt;/em&gt;, Deming presents the following points for transforming business effectiveness:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;Create constancy of purpose toward improvement of product and service, with the aim to become competitive, to stay in business and to provide jobs.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Adopt the new philosophy. We are in a new economic age. Western management must awaken to the challenge, must learn their responsibilities, and take on leadership for change.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Cease dependence on inspection to achieve quality. Eliminate the need for massive inspection by building quality into the product in the first place.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;End the practice of awarding business on the basis of a price tag. Instead, minimize total cost. Move towards a single supplier for any one item, on a long-term relationship of loyalty and trust.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Improve constantly and forever the system of production and service, to improve quality and productivity, and thus constantly decrease costs.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Institute training on the job.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Institute leadership. The aim of supervision should be to help people and machines and gadgets do a better job. Supervision of management is in need of overhaul, as well as supervision of production workers.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Drive out fear, so that everyone may work effectively for the company.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Break down barriers between departments. People in research, design, sales, and production must work as a team, to foresee problems of production and usage that may be encountered with the product or service.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Eliminate slogans, exhortations, and targets for the work force asking for zero defects and new levels of productivity. Such exhortations only create adversarial relationships, as the bulk of the causes of low quality and low productivity belong to the system and thus lie beyond the power of the work force.&lt;br&gt;&lt;br&gt;a) Eliminate work standards (quotas) on the factory floor. Substitute with leadership.&lt;br&gt;&lt;br&gt;b) Eliminate management by objective. Eliminate management by numbers and numerical goals. Instead substitute with leadership.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Remove barriers that rob the hourly worker of his right to pride of workmanship. The responsibility of supervisors must be changed from sheer numbers to quality.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Remove barriers that rob people in management and in engineering of their right to pride of workmanship. This means, &lt;em&gt;inter alia&lt;/em&gt;, abolishment of the annual or merit rating and of management by objectives.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Institute a vigorous program of education and self-improvement.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Put everybody in the company to work to accomplish the transformation. The transformation is everybody&#39;s job.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h2 id=sources-and-interesting-reads tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/10/the-fathers-of-quality-deming-and-shewhart/#sources-and-interesting-reads class=header-anchor&gt;&lt;span&gt;Sources and interesting reads&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://tvtropes.org/pmwiki/pmwiki.php/Analysis/JapanTakesOverTheWorld&gt;TV Tropes - Japan Takes Over The World - Analysis&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://en.wikipedia.org/wiki/List_of_countries_by_largest_historical_GDP&gt;Wikipedia - List of countries by largest historical GDP&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://popculturereferences.com/wp-content/uploads/2021/11/its-a-rolex.jpg&gt;Die Hard characters photo&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://www.bizmanualz.com/improve-business-processes/how-to-use-control-charts-for-continuous-improvement.html&gt;BizManualz - How to Use Control Charts for Continuous Improvement&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://en.wikipedia.org/wiki/William_Edwards_Deming&gt;Wikipedia - William Edwards Deming&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://en.wikipedia.org/wiki/Walter_A._Shewhart&gt;Wikipedia - Walter Andrew Shewhart&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://deming.org/deming-the-man/ &gt;The Deming Institute - The Man&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://www.nae.edu/19579/19581/51314/51341/188359/W-EDWARDS-DEMING-19001993&gt;National Academy of Engineering - W. Edwards Deming&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=vcG_Pmt_Ny4&quot;&gt;YouTube - NBC documentary &quot;If Japan Can, Why Can&#39;t We?&quot; (1980)&lt;/a&gt; &lt;strong&gt;(recommended)&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=http://hclectures.blogspot.com/1970/08/demings-1950-lecture-to-Japanese.html&gt;Deming&#39;s 1950 Lecture to Japanese Management&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://specinnovations.com/blog/ford-vs.-mazda-transmissions&gt;Spec Innovations - Ford vs. Mazda transmissions&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://elsmar.com/elsmarqualityforum/threads/the-famous-ford-study-of-mazda-transmissions-can-the-characteristic-be-measured.1263/ &gt;Elsmar Quality Forum - The Famous Ford Study of Mazda Transmissions - Can the characteristic be measured?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://www.nytimes.com/2001/06/13/business/management-ford-embraces-six-sigma.html&gt;New York Times - Management: Ford Embraces Six Sigma (06/13/2001)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Collation and encoding in databases</title>
    <link href="https://alexandrehtrb.github.io/posts/2024/08/collation-and-encoding-in-databases/" />
    <updated>2024-08-29T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2024/08/collation-and-encoding-in-databases/</id>
    <content type="html">&lt;h2 id=introduction tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/collation-and-encoding-in-databases/#introduction class=header-anchor&gt;&lt;span&gt;Introduction&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Every information in a computer is stored and processed in its binary number representation.&lt;/p&gt;&lt;p&gt;But what about texts? A text is a sequence of characters, a character being a letter or a symbol. Each character is represented by a binary number and the character-number mapping is called &lt;strong&gt;encoding&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;The table below is for Windows-1252 encoding, which addresses 255 possible characters, each represented by one byte. You can see this table on Windows Character Map (Win+R, &lt;code&gt;charmap&lt;/code&gt;).&lt;/p&gt;&lt;img alt=&quot;Windows-1252 encoding table&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2024_08_windows_1252_table.gif&gt;&lt;p&gt;The &lt;strong&gt;collation&lt;/strong&gt; is the ordering and comparison rule for texts. It also determines which encoding is used for storage.&lt;/p&gt;&lt;p&gt;On Microsoft SQL Server, in the collation&#39;s name, CI / CS means case (in)sensitive; AI / AS, accent (in)sensitive. With a case-insensitive (CI) collation, for example, searching for either &lt;code&gt;silva&lt;/code&gt; or &lt;code&gt;SILVA&lt;/code&gt; yields the same results; with an accent-insensitive (AI) collation, &lt;code&gt;Acucar&lt;/code&gt; and &lt;code&gt;Açúcar&lt;/code&gt; are considered equal for comparisons.&lt;/p&gt;&lt;p&gt;Accent-insensitive is insensitive actually for all the &lt;a href=https://en.wikipedia.org/wiki/Diacritic&gt;diacritics&lt;/a&gt; of a language, like &lt;em&gt;cedillas&lt;/em&gt; (ç, ş) and accents (é, ã, ô, etc). Some older collations do not cover all diacritics on comparisons (&lt;a href=https://dba.stackexchange.com/questions/343799/a-collation-that-ignores-cedillas-for-comparison&gt;link&lt;/a&gt;), so newer collations should be preferred.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [Name],&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  COLLATIONPROPERTY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;( [Name], &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;LCID&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; ) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [LCID],&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  COLLATIONPROPERTY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;( [Name], &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;CodePage&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; ) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [CodePage]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; sys.fn_helpcollations()&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;ORDER BY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Name];&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Name&lt;/th&gt;&lt;th style=text-align:center&gt;Encoding&lt;/th&gt;&lt;th style=text-align:center&gt;Compares casing&lt;/th&gt;&lt;th style=text-align:center&gt;Compares accents&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Latin1_General_&lt;br&gt;CI_AS&lt;/td&gt;&lt;td style=text-align:center&gt;Windows-1252&lt;/td&gt;&lt;td style=text-align:center&gt;No&lt;/td&gt;&lt;td style=text-align:center&gt;Yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Latin1_General_&lt;br&gt;100_CI_AS_&lt;br&gt;KS_SC_UTF8&lt;/td&gt;&lt;td style=text-align:center&gt;UTF-8 (65001)&lt;/td&gt;&lt;td style=text-align:center&gt;No&lt;/td&gt;&lt;td style=text-align:center&gt;Yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Latin1_General_&lt;br&gt;100_CS_AS_&lt;br&gt;KS_SC_UTF8&lt;/td&gt;&lt;td style=text-align:center&gt;UTF-8 (65001)&lt;/td&gt;&lt;td style=text-align:center&gt;Yes&lt;/td&gt;&lt;td style=text-align:center&gt;Yes&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2 id=unicode%2C-utf-8-and-utf-16 tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/collation-and-encoding-in-databases/#unicode%2C-utf-8-and-utf-16 class=header-anchor&gt;&lt;span&gt;Unicode, UTF-8 and UTF-16&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Unicode is a table that defines a number for each character, covering symbols, digits and letters from many languages. The number attributed to a character is called &lt;strong&gt;code point&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;UTF-8 and UTF-16 are encodings that follow Unicode. Basically, they are ways of storing those numbers into bytes.&lt;/p&gt;&lt;p&gt;UTF-16 uses 2 bytes for most chars and 4 for those above the standard range. This encoding is used in the strings of most programming languages.&lt;/p&gt;&lt;p&gt;UTF-8 uses a variable number of bytes, starting at 1 and up to 4 for a char. It&#39;s the main encoding on the Internet.&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Unicode range&lt;/th&gt;&lt;th style=text-align:center&gt;Groups&lt;/th&gt;&lt;th style=text-align:center&gt;Bytes per char, UTF-8&lt;/th&gt;&lt;th style=text-align:center&gt;Bytes per char, UTF-16&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;0x0000 - 0x007F&lt;/td&gt;&lt;td style=text-align:center&gt;Basic latin alphabet, arabic digits (0-9), basic keyboard symbols&lt;/td&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;0x0080 - 0x07FF&lt;/td&gt;&lt;td style=text-align:center&gt;Extended latin alphabet, greek, cyrillic, arabic, hebrew&lt;/td&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;0x0800 - 0xFFFF&lt;/td&gt;&lt;td style=text-align:center&gt;Japanese and chinese ideograms; varied symbols; math operators&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;0x010000 - 0x10FFFF&lt;/td&gt;&lt;td style=text-align:center&gt;Ancient writing pictograms (e.g. egyptian hieroglyphs); emojis; musical symbols&lt;/td&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;The choice of encoding directly affects the size of text storage. If most characters lie in the basic latin range, UTF-8 is better, because it uses fewer bytes than UTF-16; however, if it&#39;s an asian text, UTF-16 is the best, because each character occupies 2 bytes, instead of 3 on UTF-8.&lt;/p&gt;&lt;p&gt;The table below shows how an Unicode number is converted to UTF-8 or UTF-16, for each range above.&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Example character&lt;/th&gt;&lt;th style=text-align:center&gt;Code point, in binary&lt;/th&gt;&lt;th style=text-align:center&gt;In UTF-8&lt;/th&gt;&lt;th style=text-align:center&gt;In UTF-16&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;P&lt;/strong&gt; (0x0050)&lt;/td&gt;&lt;td style=text-align:center&gt;00110010&lt;/td&gt;&lt;td style=text-align:center&gt;00110010&lt;/td&gt;&lt;td style=text-align:center&gt;00000000 00110010&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;Ω&lt;/strong&gt; (0x03A9)&lt;/td&gt;&lt;td style=text-align:center&gt;00000&lt;span style=color:green&gt;011&lt;/span&gt; &lt;span style=color:red&gt;1010&lt;/span&gt;&lt;span style=color:purple&gt;1001&lt;/span&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;110&lt;span style=color:green&gt;011&lt;/span&gt;&lt;span style=color:red&gt;10&lt;/span&gt; 10&lt;span style=color:red&gt;10&lt;/span&gt;&lt;span style=color:purple&gt;1001&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;00000011 10101001&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;€&lt;/strong&gt; (0x20AC)&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;span style=color:#00f&gt;0010&lt;/span&gt;&lt;span style=color:green&gt;0000&lt;/span&gt; &lt;span style=color:red&gt;1010&lt;/span&gt;&lt;span style=color:purple&gt;1100&lt;/span&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;1110&lt;span style=color:#00f&gt;0010&lt;/span&gt; 10&lt;span style=color:green&gt;0000&lt;/span&gt;&lt;span style=color:red&gt;10&lt;/span&gt; 10&lt;span style=color:red&gt;10&lt;/span&gt;&lt;span style=color:purple&gt;1100&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;00100000 10101100&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;🐎 (0x1F40E)&lt;/td&gt;&lt;td style=text-align:center&gt;000&lt;span style=color:#2e8b57&gt;0&lt;/span&gt;&lt;span style=color:sienna&gt;0001&lt;/span&gt; &lt;span style=color:#00f&gt;1111&lt;/span&gt;&lt;span style=color:green&gt;0100&lt;/span&gt; &lt;span style=color:red&gt;0000&lt;/span&gt;&lt;span style=color:purple&gt;1110&lt;/span&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;11110&lt;span style=color:#2e8b57&gt;0&lt;/span&gt;&lt;span style=color:sienna&gt;00&lt;/span&gt; 10&lt;span style=color:sienna&gt;01&lt;/span&gt;&lt;span style=color:#00f&gt;1111&lt;/span&gt; 10&lt;span style=color:green&gt;0100&lt;/span&gt;&lt;span style=color:red&gt;00&lt;/span&gt; 10&lt;span style=color:red&gt;00&lt;/span&gt;&lt;span style=color:purple&gt;1110&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;110110&lt;span style=color:#c71585&gt;00&lt;/span&gt; &lt;span style=color:#c71585&gt;00&lt;/span&gt;&lt;span style=color:#00f&gt;1111&lt;/span&gt;&lt;span style=color:green&gt;01&lt;/span&gt; 110111&lt;span style=color:green&gt;00&lt;/span&gt; &lt;span style=color:red&gt;0000&lt;/span&gt;&lt;span style=color:purple&gt;1110&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;The logic for UTF-16 code points above 0x010000 is:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;U = code point&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;W1 = 2 upper bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;W2 = 2 lower bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;W = U - 0x10000 &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;W = yyyyyyyyyyxxxxxxxxxx (20 binary digits)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;W1 = 110110yy yyyyyyyy&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;W2 = 110111xx xxxxxxxx&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;-&gt; there is no risk of W1 and W2 being mistaken for &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;other characters because the possible interval for them &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;is protected on the Unicode table.&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=texts-in-sql-databases tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/collation-and-encoding-in-databases/#texts-in-sql-databases class=header-anchor&gt;&lt;span&gt;Texts in SQL databases&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;CHAR and NCHAR store fixed-size texts; VARCHAR and NVARCHAR store variable-sized texts.&lt;/p&gt;&lt;p&gt;NCHAR and NVARCHAR are types present on SQL Server and the &#39;N&#39; indicates that they store text in UTF-16 encoding. CHAR and VARCHAR, on the other hand, store according to the encoding of the database&#39;s collation.&lt;/p&gt;&lt;p&gt;The storage size is specified on the column type declaration, such as &lt;code&gt;NVARCHAR(n)&lt;/code&gt;. &lt;em&gt;Many people think that n is the number of characters, but that is not true.&lt;/em&gt; For CHAR and VARCHAR, n defines the size in bytes; for NCHAR and NVARCHAR, n is the size in byte-pairs (x2).&lt;/p&gt;&lt;h3&gt;Practical example&lt;/h3&gt;&lt;p&gt;Let&#39;s have two databases, one with the Latin1_General_CI_AS collation (Windows-1252 encoding) and another with Latin1_General_100_CI_AS_KS_SC_UTF8 collation (UTF-8 encoding). For each of them, we will compare the storage sizes between VARCHAR and NVARCHAR, for texts in basic and extended latin alphabet, greek, japanese and emojis. Below, the script to run:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Person] (&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;VARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;24&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NOT NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [NameUtf16] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;24&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NOT NULL&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Person] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;VALUES&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Pericles&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Pericles&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- latin without accent&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Péricles&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Péricles&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- latin with accent&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;N&#39;Περικλῆς&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;N&#39;Περικλῆς&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- greek&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;N&#39;美しいキモノ&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;N&#39;美しいキモノ&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- japanese katakana&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;N&#39;Santa Claus 🎅&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;N&#39;Santa Claus 🎅&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;); &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- with emoji&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- the N prefix is necessary for unicode strings&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [Name], &lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;DATALENGTH&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;([Name]) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [SizeInBytes],&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [NameUtf16], &lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;DATALENGTH&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;([NameUtf16]) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [SizeInBytes]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Person];&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;DROP&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Person];&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Latin1 General CI AS&lt;/h3&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;VARCHAR name&lt;/th&gt;&lt;th style=text-align:center&gt;Size in bytes&lt;/th&gt;&lt;th style=text-align:center&gt;NVARCHAR name&lt;/th&gt;&lt;th style=text-align:center&gt;Size in bytes&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Pericles&lt;/td&gt;&lt;td style=text-align:center&gt;8&lt;/td&gt;&lt;td style=text-align:center&gt;Pericles&lt;/td&gt;&lt;td style=text-align:center&gt;16&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Péricles&lt;/td&gt;&lt;td style=text-align:center&gt;8&lt;/td&gt;&lt;td style=text-align:center&gt;Péricles&lt;/td&gt;&lt;td style=text-align:center&gt;16&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;?e??????&lt;/td&gt;&lt;td style=text-align:center&gt;8&lt;/td&gt;&lt;td style=text-align:center&gt;Περικλῆς&lt;/td&gt;&lt;td style=text-align:center&gt;16&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;??????&lt;/td&gt;&lt;td style=text-align:center&gt;6&lt;/td&gt;&lt;td style=text-align:center&gt;美しいキモノ&lt;/td&gt;&lt;td style=text-align:center&gt;12&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Santa Claus ??&lt;/td&gt;&lt;td style=text-align:center&gt;14&lt;/td&gt;&lt;td style=text-align:center&gt;Santa Claus 🎅&lt;/td&gt;&lt;td style=text-align:center&gt;28&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Note that Windows-1252 encoding does not support greek and japanese characters, nor emojis, that are replaced by &#39;?&#39;. Despite that, it handles very well latin words, with only 1 byte per letter, even on those with accents or &lt;em&gt;cedillas&lt;/em&gt;.&lt;/p&gt;&lt;h3&gt;Latin1 General 100 CI AS KS SC UTF8&lt;/h3&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;VARCHAR name&lt;/th&gt;&lt;th style=text-align:center&gt;Size in bytes&lt;/th&gt;&lt;th style=text-align:center&gt;NVARCHAR name&lt;/th&gt;&lt;th style=text-align:center&gt;Size in bytes&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Pericles&lt;/td&gt;&lt;td style=text-align:center&gt;8&lt;/td&gt;&lt;td style=text-align:center&gt;Pericles&lt;/td&gt;&lt;td style=text-align:center&gt;16&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Péricles&lt;/td&gt;&lt;td style=text-align:center&gt;9&lt;/td&gt;&lt;td style=text-align:center&gt;Péricles&lt;/td&gt;&lt;td style=text-align:center&gt;16&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Περικλῆς&lt;/td&gt;&lt;td style=text-align:center&gt;17&lt;/td&gt;&lt;td style=text-align:center&gt;Περικλῆς&lt;/td&gt;&lt;td style=text-align:center&gt;16&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;美しいキモノ&lt;/td&gt;&lt;td style=text-align:center&gt;18&lt;/td&gt;&lt;td style=text-align:center&gt;美しいキモノ&lt;/td&gt;&lt;td style=text-align:center&gt;12&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Santa Claus 🎅&lt;/td&gt;&lt;td style=text-align:center&gt;16&lt;/td&gt;&lt;td style=text-align:center&gt;Santa Claus 🎅&lt;/td&gt;&lt;td style=text-align:center&gt;28&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;With an UTF-8 collation, the VARCHAR field successfully supported all characters and had a higher efficiency for most cases. The third name, Περικλῆς, needed 17 bytes because the letter ῆ (unicode 0x1FC6) is from ancient greek and requires 3 bytes in UTF-8 encoding. For japanese katakana, UTF-16 proved more efficient.&lt;/p&gt;&lt;h2 id=sources-and-interesting-reads tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/collation-and-encoding-in-databases/#sources-and-interesting-reads class=header-anchor&gt;&lt;span&gt;Sources and interesting reads&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://www.charset.org/charsets/windows-1252&gt;Windows-1252 table&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://en.wikipedia.org/wiki/UTF-8&gt;Wikipedia - UTF-8&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://en.wikipedia.org/wiki/UTF-16&gt;Wikipedia - UTF-16&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://symbl.cc/en/unicode-table/ &gt;Unicode table&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://www.unicode.org/emoji/charts/full-emoji-list.html&gt;Emojis Unicode&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://techcommunity.microsoft.com/t5/azure-sql-blog/introducing-utf-8-support-for-azure-sql-database/ba-p/757748&gt;Azure SQL Blog - Introducing UTF-8 support for Azure SQL Database&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-ver16#utf8&quot;&gt;Microsoft Learn - UTF-8 support on SQL Server&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>SQL iceberg</title>
    <link href="https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/" />
    <updated>2024-08-14T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/</id>
    <content type="html">&lt;h2 id=introduction tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#introduction class=header-anchor&gt;&lt;span&gt;Introduction&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The SQL language, &lt;em&gt;Structured Query Language&lt;/em&gt;, first emerged in 1974 and is one of the leading languages to this day, when it comes to databases.&lt;/p&gt;&lt;p&gt;SQL evolved a lot throughout the years and especially over the last two decades, with modern data organization techniques, that came up as a response to new competitors (NoSQL) and new needs (analytics, data warehouse, cloud computing).&lt;/p&gt;&lt;p&gt;This article is a SQL cheatsheet, covering some of the most common commands to those that are rare and have interesting uses. This list tries to be easy to understand for beginners and for those who already have some familiarity with the language.&lt;/p&gt;&lt;p&gt;The examples here are for Microsoft SQL Server, but most of them apply in a similar or equal way for other databases, such as PostgreSQL, MySQL and Oracle.&lt;br&gt;&lt;/p&gt;&lt;img alt=&quot;SQL iceberg&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_08_sql_iceberg.jpg class=my-4&gt;&lt;br&gt;&lt;p&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#before-we-begin&gt;&lt;strong&gt;Before we begin&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#installation&gt;Installation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#sample-tables&gt;Sample tables&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#reads-and-queries&gt;&lt;strong&gt;Reads and queries&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#select&gt;SELECT&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#left%2C-right%2C-inner-joins&gt;LEFT, RIGHT, INNER JOINS&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#views&gt;VIEWS&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#group-by%2C-having&gt;GROUP BY, HAVING&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#union%2C-intersect%2C-except&gt;UNION, INTERSECT, EXCEPT&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#subqueries&gt;SUBQUERIES&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#self-join&gt;SELF JOIN&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#cross-join&gt;CROSS JOIN&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#pivot&gt;PIVOT&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#rollup%2C-cube%2C-grouping-sets&gt;ROLLUP, CUBE, GROUPING SETS&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#window-function&gt;WINDOW FUNCTION&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#nolock&gt;NOLOCK&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#data-changes&gt;&lt;strong&gt;Data changes&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#insert%2C-update%2C-delete&gt;INSERT, UPDATE, DELETE&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#stored-procedures&gt;STORED PROCEDURES&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#merge&gt;MERGE&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#bulk-insert&gt;BULK INSERT&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#table-structuring&gt;&lt;strong&gt;Table structuring&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#primary-key%2C-foreign-key&gt;PRIMARY KEY, FOREIGN KEY&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#indexes&gt;INDEXES&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#unique&gt;UNIQUE&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#sparse&gt;SPARSE&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#columnstore&gt;COLUMNSTORE&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#special&gt;&lt;strong&gt;Special&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#import-dlls&gt;IMPORT DLLs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#json&gt;JSON&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#applocks&gt;APPLOCKS&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#view-execution-plan&gt;VIEW EXECUTION PLAN&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#final-conclusions&gt;&lt;strong&gt;Final conclusions&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;br&gt;&lt;h1 id=before-we-begin tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#before-we-begin class=header-anchor&gt;&lt;span&gt;Before we begin&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;h2 id=installation tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#installation class=header-anchor&gt;&lt;span&gt;Installation&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;To test the examples of this article, I recommend installing SQL Server (&lt;a href=&quot;https://go.microsoft.com/fwlink/?LinkID=866662&quot;&gt;download&lt;/a&gt;) and SQL Server Management Studio (SSMS) (&lt;a href=https://aka.ms/ssmsfullsetup&gt;download&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;After the installations, enter SSMS and login in your instance:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Windows Authentication&lt;/li&gt;&lt;li&gt;Server name: &lt;code&gt;.&lt;/code&gt; (dot)&lt;/li&gt;&lt;li&gt;Check &lt;em&gt;Trust server certificate&lt;/em&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;These options may differ according to the configuration during setup.&lt;/p&gt;&lt;p&gt;Then, choose a database in the left panel; if there are none, click with the mouse right button on &lt;em&gt;Databases&lt;/em&gt; and create one.&lt;/p&gt;&lt;p&gt;To write a SQL script, click on &lt;em&gt;New query&lt;/em&gt;, in the top menu. To run, press F5 or click on &lt;em&gt;Execute&lt;/em&gt;.&lt;/p&gt;&lt;h2 id=sample-tables tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#sample-tables class=header-anchor&gt;&lt;span&gt;Sample tables&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Let&#39;s start with two tables that will be used in our examples: tables &lt;strong&gt;Fruit&lt;/strong&gt; and &lt;strong&gt;Family&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;Table &lt;code&gt;[dbo].[Fruit]&lt;/code&gt;:&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Id&lt;/th&gt;&lt;th style=text-align:center&gt;Name&lt;/th&gt;&lt;th style=text-align:center&gt;IdFamily&lt;/th&gt;&lt;th style=text-align:center&gt;Calories*&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;td style=text-align:center&gt;Coconut&lt;/td&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;td style=text-align:center&gt;354&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;td style=text-align:center&gt;Date&lt;/td&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;td style=text-align:center&gt;282&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;Strawberry&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;32&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;Watermelon&lt;/td&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;td style=text-align:center&gt;30&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;5&lt;/td&gt;&lt;td style=text-align:center&gt;Passionfruit&lt;/td&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;97&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;6&lt;/td&gt;&lt;td style=text-align:center&gt;Cherry&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;64&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;7&lt;/td&gt;&lt;td style=text-align:center&gt;Pineapple&lt;/td&gt;&lt;td style=text-align:center&gt;5&lt;/td&gt;&lt;td style=text-align:center&gt;48&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;8&lt;/td&gt;&lt;td style=text-align:center&gt;Apple&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;52&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;* Calories per 100g. Source: &lt;a href=https://www.mundoboaforma.com.br/tabela-de-calorias-das-frutas/ &gt;Mundo Boa Forma&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Table &lt;code&gt;[dbo].[Family]&lt;/code&gt;:&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Id&lt;/th&gt;&lt;th style=text-align:center&gt;Family&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;td style=text-align:center&gt;Arecaceae&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;td style=text-align:center&gt;Cucurbitaceae&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;Rosaceae&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;Passifloraceae&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;5&lt;/td&gt;&lt;td style=text-align:center&gt;Bromeliaceae&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;6&lt;/td&gt;&lt;td style=text-align:center&gt;Malvaceae&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;To create them, run the following SQL script in your database.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Family](&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [Id] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NOT NULL&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; IDENTITY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;PRIMARY KEY&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; CLUSTERED&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;64&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NOT NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Family] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;VALUES&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Arecaceae&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Cucurbitaceae&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Rosaceae&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Passifloraceae&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Bromeliaceae&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Malvaceae&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit](&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [Id] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NOT NULL&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; IDENTITY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;PRIMARY KEY&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; CLUSTERED&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;64&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NOT NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [IdFamily] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NOT NULL&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; FOREIGN KEY&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; REFERENCES&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Family](Id),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [Calories] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NOT NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;VALUES&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Coconut&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;354&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Date&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;282&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Strawberry&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;32&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Watermelon&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;30&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Passionfruit&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;97&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Cherry&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;64&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Pineapple&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;5&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;48&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Apple&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;52&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;h1 id=reads-and-queries tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#reads-and-queries class=header-anchor&gt;&lt;span&gt;Reads and queries&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;h2 id=select tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#select class=header-anchor&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Gets data in a tabular structure.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Name], [Calories]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Calories] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 50&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Returns:&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Name&lt;/th&gt;&lt;th style=text-align:center&gt;Calories&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Strawberry&lt;/td&gt;&lt;td style=text-align:center&gt;32&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Watermelon&lt;/td&gt;&lt;td style=text-align:center&gt;30&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Pineapple&lt;/td&gt;&lt;td style=text-align:center&gt;48&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;code&gt;*&lt;/code&gt; means all columns:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Calories] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 50&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Id&lt;/th&gt;&lt;th style=text-align:center&gt;Name&lt;/th&gt;&lt;th style=text-align:center&gt;IdFamily&lt;/th&gt;&lt;th style=text-align:center&gt;Calories&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;Strawberry&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;32&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;Watermelon&lt;/td&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;td style=text-align:center&gt;30&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;7&lt;/td&gt;&lt;td style=text-align:center&gt;Pineapple&lt;/td&gt;&lt;td style=text-align:center&gt;5&lt;/td&gt;&lt;td style=text-align:center&gt;48&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2 id=left%2C-right%2C-inner-joins tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#left%2C-right%2C-inner-joins class=header-anchor&gt;&lt;span&gt;LEFT, RIGHT, INNER JOINS&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Interlaces two or more tables by reference columns; this interlacing can be used for queries, insertions, updates and deletions.&lt;/p&gt;&lt;p&gt;Here we&#39;ll focus only on INNER JOIN and LEFT JOIN.&lt;/p&gt;&lt;p&gt;&lt;picture class=my-4&gt;&lt;source alt=&quot;Different types of JOINs on SQL&quot; srcset=https://alexandrehtrb.github.io/assets/img/posts/2024_08_sql_joins.avif type=image/avif&gt;&lt;img alt=&quot;Different types of JOINs on SQL&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_08_sql_joins.png&gt;&lt;/picture&gt;&lt;/p&gt;&lt;h3&gt;INNER JOIN&lt;/h3&gt;&lt;p&gt;&lt;code&gt;INNER JOIN&lt;/code&gt; is a perfect intersecction, that is, the interlaced values must exist in both tables. If it exists in a line of table X, but with no corresponding line in another table Y, the line of table X is not considered. Example:&lt;/p&gt;&lt;p&gt;Table &lt;code&gt;[dbo].[Fruit]&lt;/code&gt;:&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Id&lt;/th&gt;&lt;th style=text-align:center&gt;Name&lt;/th&gt;&lt;th style=text-align:center&gt;&lt;strong&gt;&lt;mark&gt;IdFamily&lt;/mark&gt;&lt;/strong&gt;&lt;/th&gt;&lt;th style=text-align:center&gt;Calories&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;Strawberry&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;&lt;mark&gt;3&lt;/mark&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;32&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;Watermelon&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;&lt;mark&gt;2&lt;/mark&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;30&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;7&lt;/td&gt;&lt;td style=text-align:center&gt;Pineapple&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;&lt;mark&gt;5&lt;/mark&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;48&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Table &lt;code&gt;[dbo].[Family]&lt;/code&gt;:&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;&lt;strong&gt;&lt;mark&gt;Id&lt;/mark&gt;&lt;/strong&gt;&lt;/th&gt;&lt;th style=text-align:center&gt;Family&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;&lt;mark&gt;2&lt;/mark&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;Cucurbitaceae&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;&lt;mark&gt;3&lt;/mark&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;Rosaceae&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;&lt;mark&gt;5&lt;/mark&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;Bromeliaceae&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;SQL query:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    fr.[Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Name],&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    fa.[Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Family]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit] fr&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INNER JOIN&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Family] fa &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;ON&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fr.[IdFamily] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fa.[Id]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fr.[Calories] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 50&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Returns:&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Name&lt;/th&gt;&lt;th style=text-align:center&gt;Family&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Strawberry&lt;/td&gt;&lt;td style=text-align:center&gt;Rosaceae&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Watermelon&lt;/td&gt;&lt;td style=text-align:center&gt;Cucurbitaceae&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Pineapple&lt;/td&gt;&lt;td style=text-align:center&gt;Bromeliaceae&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h3&gt;LEFT / RIGHT JOIN&lt;/h3&gt;&lt;p&gt;&lt;code&gt;LEFT JOIN&lt;/code&gt; and &lt;code&gt;RIGHT JOIN&lt;/code&gt; are imperfect intersecctions, such that the correspondence value is allowed to not exist in one of the tables; if it doesn&#39;t exist, then values from the table with no correspondence will come null.&lt;/p&gt;&lt;p&gt;In the tables above, the &lt;em&gt;Malvaceae&lt;/em&gt; family (id = 6) has no registered fruit.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    fa.[Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Family],&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    fr.[Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Fruit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Family] fa&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;LEFT JOIN&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit] fr &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;ON&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fr.[IdFamily] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fa.[Id]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Family&lt;/th&gt;&lt;th style=text-align:center&gt;Fruit&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Arecaceae&lt;/td&gt;&lt;td style=text-align:center&gt;Coconut&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Arecaceae&lt;/td&gt;&lt;td style=text-align:center&gt;Date&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Cucurbitaceae&lt;/td&gt;&lt;td style=text-align:center&gt;Watermelon&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Rosaceae&lt;/td&gt;&lt;td style=text-align:center&gt;Strawberry&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Rosaceae&lt;/td&gt;&lt;td style=text-align:center&gt;Cherry&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Rosaceae&lt;/td&gt;&lt;td style=text-align:center&gt;Apple&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Passifloraceae&lt;/td&gt;&lt;td style=text-align:center&gt;Passionfruit&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Bromeliaceae&lt;/td&gt;&lt;td style=text-align:center&gt;Pineapple&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Malvaceae&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;code&gt;NULL&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2 id=views tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#views class=header-anchor&gt;&lt;span&gt;VIEWS&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;VIEWS are encapsulated queries: instead of always typing a complex query, you can &quot;alias&quot; this query with a view, which simplifies the call. This technique is good for abstracting logic and to control access permissions — an user can call the view, but be blocked from querying the source tables.&lt;/p&gt;&lt;p&gt;View creation:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; OR&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ALTER&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; VIEW [dbo].[ViewGetFruits] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  SELECT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    fr.[Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Fruit],&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    fa.[Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Family]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit] fr&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  INNER JOIN&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Family] fa &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;ON&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fr.[IdFamily] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fa.[Id]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To run:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- the view behaves like a table&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; *&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[ViewGetFruits]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=group-by%2C-having tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#group-by%2C-having class=header-anchor&gt;&lt;span&gt;GROUP BY, HAVING&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;GROUP BY is a grouping instruction and HAVING is a filter applied over groups.&lt;/p&gt;&lt;p&gt;Columns returned by a SELECT with grouping must be specified on the GROUP BY, or be in aggregation functions, like counts, sums, averages, etc.&lt;/p&gt;&lt;p&gt;Example:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fr.[IdFamily], &lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;COUNT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(fr.[Id]) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; NumberOfFruits&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit] fr&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GROUP BY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fr.[IdFamily]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;IdFamily&lt;/th&gt;&lt;th style=text-align:center&gt;NumberOfFruits&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;5&lt;/td&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;With inner join and filter over the groups:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fa.[Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Family], &lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;COUNT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(fr.[Id]) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; NumberOfFruits&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit] fr&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INNER JOIN&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Family] fa &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;ON&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fr.[IdFamily] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fa.[Id]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GROUP BY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fa.[Name]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;HAVING&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; COUNT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(fr.[Id]) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 2&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt; -- family w/ 2 or more fruits&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Family&lt;/th&gt;&lt;th style=text-align:center&gt;NumberOfFruits&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Arecaceae&lt;/td&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Rosaceae&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2 id=union%2C-intersect%2C-except tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#union%2C-intersect%2C-except class=header-anchor&gt;&lt;span&gt;UNION, INTERSECT, EXCEPT&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;These are set operators (see &lt;a href=https://en.wikipedia.org/wiki/Set_theory&gt;set theory&lt;/a&gt; in mathematics). They are different from the interlacing that happens in JOINs — while in JOINs the interlacing is between columns, with sets the interlacing is between lines. The examples below show this visually.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;UNION: Returns elements that belong to one set &lt;strong&gt;or&lt;/strong&gt; another.&lt;/li&gt;&lt;li&gt;INTERSECT: Returns elements that belong to one set &lt;strong&gt;and&lt;/strong&gt; another, at the same time.&lt;/li&gt;&lt;li&gt;EXCEPT: Returns elements that belong to one set, &lt;strong&gt;but not to&lt;/strong&gt; another.&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;DECLARE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @a &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (X &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @a &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;VALUES&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;5&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;DECLARE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @b &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (X &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @b &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;VALUES&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;6&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; *&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @a&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;UNION&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt; -- INTERSECT, EXCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; *&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @b&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;A&lt;/th&gt;&lt;th style=text-align:center&gt;B&lt;/th&gt;&lt;th style=text-align:center&gt;UNION&lt;/th&gt;&lt;th style=text-align:center&gt;INTERSECT&lt;/th&gt;&lt;th style=text-align:center&gt;EXCEPT&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;6&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;-&lt;/td&gt;&lt;td style=text-align:center&gt;5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;-&lt;/td&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;-&lt;/td&gt;&lt;td style=text-align:center&gt;-&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;5&lt;/td&gt;&lt;td style=text-align:center&gt;-&lt;/td&gt;&lt;td style=text-align:center&gt;5&lt;/td&gt;&lt;td style=text-align:center&gt;-&lt;/td&gt;&lt;td style=text-align:center&gt;-&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;-&lt;/td&gt;&lt;td style=text-align:center&gt;-&lt;/td&gt;&lt;td style=text-align:center&gt;6&lt;/td&gt;&lt;td style=text-align:center&gt;-&lt;/td&gt;&lt;td style=text-align:center&gt;-&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;blockquote&gt;&lt;p&gt;Why use an UNION when I can just write &lt;code&gt;WHERE criterion1 OR criterion2&lt;/code&gt; ?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Sometimes we want to unite lines from different tables:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; *&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Table1 &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; criterion1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;UNION&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; *&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Table2 &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; criterion2&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;What is UNION ALL?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;In set theory, a set cannot have repeated elements. However, in SQL queries, sometimes we want to allow duplications in a union, for that, we use UNION ALL, instead of just UNION.&lt;/p&gt;&lt;h2 id=subqueries tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#subqueries class=header-anchor&gt;&lt;span&gt;SUBQUERIES&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;These are queries that run inside others. They can be useful in more complex operations, however, whenever possible, it is best to pick joins over subqueries, for better performance.&lt;/p&gt;&lt;p&gt;In the example below, the fruit family&#39;s name is obtained through a subquery:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    fr.[Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Name],&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    (&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fa.[Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Family] fa &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fa.[Id] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fr.[IdFamily]) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Family]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit] fr&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; fr.[Calories] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 50&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=self-join tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#self-join class=header-anchor&gt;&lt;span&gt;SELF JOIN&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Is a join of table with itself. Useful for tree operations.&lt;/p&gt;&lt;p&gt;Below, we have a Employee table and an employee can be someone else&#39;s boss.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;DECLARE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @employee &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (Id &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, [Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;32&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), IdBoss &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @employee &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;VALUES&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Mark&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;John&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Michael&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Rachel&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;5&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Jessica&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  f1.[Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Employee],&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  f2.[Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Boss]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @employee f1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;LEFT JOIN&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @employee f2 &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;ON&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; f1.[IdBoss] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; f2.[Id]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;ORDER BY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; f2.[Id] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;ASC&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Employee&lt;/th&gt;&lt;th style=text-align:center&gt;Boss&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;John&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;code&gt;NULL&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Michael&lt;/td&gt;&lt;td style=text-align:center&gt;John&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Rachel&lt;/td&gt;&lt;td style=text-align:center&gt;John&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Jessica&lt;/td&gt;&lt;td style=text-align:center&gt;Rachel&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Mark&lt;/td&gt;&lt;td style=text-align:center&gt;Rachel&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2 id=cross-join tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#cross-join class=header-anchor&gt;&lt;span&gt;CROSS JOIN&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;It is the cartesian product between tables, basically, it makes all possible combinations of elements of one table to another.&lt;/p&gt;&lt;p&gt;Consider two tables, IceCream and Topping, and we want to know what combinations we can have.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;DECLARE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @icecream &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (Id &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, [Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;32&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @icecream &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;VALUES&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Strawberry&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), (&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Flake&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), (&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Chocolate&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;DECLARE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @topping &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (Id &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, [Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;32&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @topping &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;VALUES&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Chocolate syrup&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), (&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Nuts&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; i.[Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; IceCream, t.[Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Topping&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @icecream i &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CROSS JOIN&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @topping t&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;ORDER BY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; i.[Id] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;ASC&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, t.[Id] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;ASC&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;IceCream&lt;/th&gt;&lt;th style=text-align:center&gt;Topping&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Strawberry&lt;/td&gt;&lt;td style=text-align:center&gt;Chocolate syrup&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Strawberry&lt;/td&gt;&lt;td style=text-align:center&gt;Nuts&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Flake&lt;/td&gt;&lt;td style=text-align:center&gt;Chocolate syrup&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Flake&lt;/td&gt;&lt;td style=text-align:center&gt;Nuts&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Chocolate&lt;/td&gt;&lt;td style=text-align:center&gt;Chocolate syrup&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;Chocolate&lt;/td&gt;&lt;td style=text-align:center&gt;Nuts&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2 id=pivot tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#pivot class=header-anchor&gt;&lt;span&gt;PIVOT&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;picture class=my-4&gt;&lt;source alt=&quot;Ross asking to rotate the couch - Friends&quot; srcset=https://alexandrehtrb.github.io/assets/img/posts/2024_08_friends_pivot.avif type=image/avif&gt;&lt;img alt=&quot;Ross asking to rotate the couch - Friends&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_08_friends_pivot.jpg&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;The PIVOT instruction is very interesting. It transforms lines into columns, by rotating part of the table in 90º. It is very good for crossing two or more columns of a table.&lt;/p&gt;&lt;p&gt;In the example below, we have a table Sales with each line being the quantity of a product sold on a certain day. We want to visualize this in a better way, with date columns, and for that we will use PIVOT.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;DECLARE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @sales &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (IdProduct &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, Quantity &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, SalesDate &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;DATE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @sales &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;VALUES&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;5&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;52&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-05&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;902&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-05&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;196&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-06&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;212&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-06&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;488&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-07&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;384&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-07&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1121&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-08&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;49&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-08&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;88&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-09&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;12&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-09&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;5&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;98&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-09&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; *&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FROM&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [SalesDate], [IdProduct], [Quantity]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @sales&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) t&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;PIVOT(&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;  SUM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;([Quantity]) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FOR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [SalesDate] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;IN&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; ([2024-08-05],[2024-08-06],[2024-08-07],[2024-08-08],[2024-08-09])&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; pvt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;IdProduct&lt;/th&gt;&lt;th style=text-align:center&gt;2024-08-05&lt;/th&gt;&lt;th style=text-align:center&gt;2024-08-06&lt;/th&gt;&lt;th style=text-align:center&gt;2024-08-07&lt;/th&gt;&lt;th style=text-align:center&gt;2024-08-08&lt;/th&gt;&lt;th style=text-align:center&gt;2024-08-09&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;196&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;1121&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;49&lt;/td&gt;&lt;td style=text-align:center&gt;12&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;902&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;488&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;88&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;212&lt;/td&gt;&lt;td style=text-align:center&gt;384&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;5&lt;/td&gt;&lt;td style=text-align:center&gt;52&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;98&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;blockquote&gt;&lt;p&gt;What if I want to generate columns dynamically, with no fixed values for them?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;You can generate the command&#39;s text at runtime and then run it. &lt;a href=https://www.sqlshack.com/dynamic-pivot-tables-in-sql-server/ &gt;This article&lt;/a&gt; shows how to do it inside a procedure:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; PROCEDURE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; dbo.GenerateStudentsReportCards&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  @ColumnToPivot  &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;255&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  @ListToPivot   &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;255&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;BEGIN&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  DECLARE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @SqlStatement &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(MAX)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  SET&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @SqlStatement &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; N&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;    SELECT * FROM (&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;      SELECT [Student], [Subject], [Marks]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;      FROM [Grades]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;    ) StudentResults&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;    PIVOT (&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;      SUM([Marks])&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;      FOR [&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;+&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;@ColumnToPivot&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;+&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;      IN (&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;+&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;@ListToPivot&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;+&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;    ) AS PivotTable&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  EXEC&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(@SqlStatement)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;END&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To run:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;EXEC&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; dbo.GenerateStudentsReportCards&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;  N&#39;Subject&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  ,&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;N&#39;[Mathematics],[Science],[Geography]&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=rollup%2C-cube%2C-grouping-sets tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#rollup%2C-cube%2C-grouping-sets class=header-anchor&gt;&lt;span&gt;ROLLUP, CUBE, GROUPING SETS&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;These are types of groupings that also analyze subgroups.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;DECLARE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @sales &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (IdProduct &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, Quantity &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, SalesDate &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;DATE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @sales &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;VALUES&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;5&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;52&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-05&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;902&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-05&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;196&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-06&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;212&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-06&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;488&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-07&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;384&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;2024-08-07&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [SalesDate], [IdProduct], &lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;SUM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;([Quantity]) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Quantity]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @sales&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GROUP BY&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ROLLUP&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;([SalesDate],[IdProduct]) &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- CUBE, GROUPING SETS&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;ROLLUP&lt;/h3&gt;&lt;p&gt;Analyzes subgroups on a pyramid, from the right to left in the declaration. &lt;code&gt;GROUP BY ROLLUP([ColA], [ColB])&lt;/code&gt; will check:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;[ColA], [ColB] (subgroup of A and B)&lt;/li&gt;&lt;li&gt;[ColA], NULL (subgroup of A for all values of B)&lt;/li&gt;&lt;li&gt;NULL, NULL (general group)&lt;/li&gt;&lt;/ul&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;SalesDate&lt;/th&gt;&lt;th style=text-align:center&gt;IdProduct&lt;/th&gt;&lt;th style=text-align:center&gt;Quantity&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-05&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;902&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-05&lt;/td&gt;&lt;td style=text-align:center&gt;5&lt;/td&gt;&lt;td style=text-align:center&gt;52&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-05&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;954&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-06&lt;/td&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;td style=text-align:center&gt;196&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-06&lt;/td&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;212&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-06&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;408&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-07&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;488&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-07&lt;/td&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;384&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-07&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;872&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;2234&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h3&gt;CUBE&lt;/h3&gt;&lt;p&gt;Analyzes all possible subgroups. &lt;code&gt;GROUP BY CUBE([ColA], [ColB])&lt;/code&gt; will check:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;[ColA], [ColB] (subgroup of A and B)&lt;/li&gt;&lt;li&gt;[ColA], NULL (subgroup of A for all values of B)&lt;/li&gt;&lt;li&gt;NULL, [ColB] (subgroup of B for all values of A)&lt;/li&gt;&lt;li&gt;NULL, NULL (general group)&lt;/li&gt;&lt;/ul&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;SalesDate&lt;/th&gt;&lt;th style=text-align:center&gt;IdProduct&lt;/th&gt;&lt;th style=text-align:center&gt;Quantity&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-06&lt;/td&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;td style=text-align:center&gt;196&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;td style=text-align:center&gt;196&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-05&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;902&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-07&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;488&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;1390&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-06&lt;/td&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;212&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-07&lt;/td&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;384&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;596&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-05&lt;/td&gt;&lt;td style=text-align:center&gt;5&lt;/td&gt;&lt;td style=text-align:center&gt;52&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;5&lt;/td&gt;&lt;td style=text-align:center&gt;52&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;2234&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-05&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;954&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-06&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;408&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-07&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;872&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h3&gt;GROUPING SETS&lt;/h3&gt;&lt;p&gt;Analyzes the subgroups of each column, but without crossing them. &lt;code&gt;GROUP BY GROUPING SETS([ColA], [ColB])&lt;/code&gt; checks:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;[ColA], NULL (subgroup of A for all values of B)&lt;/li&gt;&lt;li&gt;NULL, [ColB] (subgroup of B for all values of A)&lt;/li&gt;&lt;/ul&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;SalesDate&lt;/th&gt;&lt;th style=text-align:center&gt;IdProduct&lt;/th&gt;&lt;th style=text-align:center&gt;Quantity&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;1&lt;/td&gt;&lt;td style=text-align:center&gt;196&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;3&lt;/td&gt;&lt;td style=text-align:center&gt;1390&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;4&lt;/td&gt;&lt;td style=text-align:center&gt;596&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;5&lt;/td&gt;&lt;td style=text-align:center&gt;52&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-05&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;954&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-06&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;408&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;2024-08-07&lt;/td&gt;&lt;td style=text-align:center&gt;NULL&lt;/td&gt;&lt;td style=text-align:center&gt;872&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2 id=window-function tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#window-function class=header-anchor&gt;&lt;span&gt;WINDOW FUNCTION&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;They are functions that generate values looking over slices (or windows) of a table. They are very useful for pagination, like product searches.&lt;/p&gt;&lt;p&gt;This is a lengthy subject and with many possibilities, which is why I will not cover it here, but, I recommend &lt;a href=https://www.sqlshack.com/use-window-functions-sql-server/ &gt;this article&lt;/a&gt; that explains very well how window functions work.&lt;/p&gt;&lt;h2 id=nolock tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#nolock class=header-anchor&gt;&lt;span&gt;NOLOCK&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;NOLOCK, or READ UNCOMMITTED, is a query hint that, as the name suggests, ignores locks.&lt;/p&gt;&lt;p&gt;A regular query uses the standard isolation level, READ COMMITTED, that reads only committed data from a table. In a table with heavy traffic (many simultaneous operations), a query may face concurrency problems with inserts, updates and deletes.&lt;/p&gt;&lt;p&gt;With the NOLOCK hint, the read does not compete with those operations. However, this reading mode includes uncommitted records, in such a way that &lt;em&gt;inconsistent data may appear in the results&lt;/em&gt;. Generally speaking, NOLOCK should be used only if there actually is a concurrency problem, and if eventual inconsistencies are tolerable. An example of usage is the extraction of analytical reports.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; *&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WITH&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NOLOCK&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Calories] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 50&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;h1 id=data-changes tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#data-changes class=header-anchor&gt;&lt;span&gt;Data changes&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;h2 id=insert%2C-update%2C-delete tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#insert%2C-update%2C-delete class=header-anchor&gt;&lt;span&gt;INSERT, UPDATE, DELETE&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Adds, modifies and excludes lines from a table.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;DECLARE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @person &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (Id &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, [Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;32&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- inserting with VALUES&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @person &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;VALUES&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Mario&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), (&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Caroline&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- inserting with SELECT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @person &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;James&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- changing name&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;UPDATE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @person&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SET&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Name] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;Maria&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Id] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- deleting person&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;DELETE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @person&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Name] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;James&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- final result&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; *&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @person&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=stored-procedures tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#stored-procedures class=header-anchor&gt;&lt;span&gt;STORED PROCEDURES&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;They are scripts that accept parameters and execute actions in the database; they can return table-valued results and numerical values.&lt;/p&gt;&lt;p&gt;The procedure below can be used to add fruits (considering the example &lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#sample-tables&gt;from the beginning&lt;/a&gt;).&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; OR&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ALTER&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; PROCEDURE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[ProcAddFruit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  @fruit &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;32&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  @family &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;32&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  @calories &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;BEGIN&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  -- checks if the fruit is already registered&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  IF&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; EXISTS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Name] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @fruit)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  BEGIN&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    RAISERROR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Fruit already registered!&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;16&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    RETURN&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;; &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- stop execution&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  END&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  -- adds fruit family if it doesn&#39;t exist&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  IF&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NOT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; EXISTS&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Family] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Name] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @family)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  BEGIN&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Family] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;VALUES&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (@family);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  END&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  -- get family id&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  DECLARE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @idFamily &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Id] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Family] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Name] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @family)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  -- adds fruit&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  INSERT INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;VALUES&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (@fruit, @idFamily, @calories);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  RETURN&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 0&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;; &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- everything OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;END&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To run:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;EXECUTE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[ProcAddFruit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  @fruit &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;Orange&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  @family &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;Rutaceae&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  @calories &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 37&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=merge tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#merge class=header-anchor&gt;&lt;span&gt;MERGE&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Allows simultaneous execution of insertions, updates and deletions, comparing a source table to a target table. This instruction is used for sincronizing different data sources. If the sincronizations are always of the same type (insertions, updates, deletes), then using these specific operations offers better performance.&lt;/p&gt;&lt;p&gt;I will not enter into details here, but, I recommend &lt;a href=https://www.sqlservertutorial.net/sql-server-basics/sql-server-merge/ &gt;this article&lt;/a&gt; for those interested.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;MERGE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; target_table &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;USING&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; source_table&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;ON&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; merge_condition&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHEN&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; MATCHED&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; THEN&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; update_statement&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHEN&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NOT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; MATCHED&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; THEN&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; insert_statement&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHEN&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NOT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; MATCHED&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; BY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; SOURCE &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;THEN&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; DELETE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=bulk-insert tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#bulk-insert class=header-anchor&gt;&lt;span&gt;BULK INSERT&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;BULK INSERT is a mass insertion of data coming from a file, usually in CSV or XML formats, or a flat file.&lt;/p&gt;&lt;p&gt;This is a strategy to move large volumes of data from one place to another, especially if flat files are chosen, because they are very compact and have very high compression rates (example: a 900MB flat file, when zipped, can be reduced to 30MB, depending on the situation).&lt;/p&gt;&lt;p&gt;Consider the flat file below. Note that the starting positions of each field are always the same on a line — fruit name (0..16), family name (16..32), calories (32..35):&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;Graviola        Annonaceae      66 &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Mamão Papaya    Caricaceae      46 &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Cambucá         Myrtaceae       66 &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Bacuri          Clusiaceae      105&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Cupuaçu         Malvaceae       49 &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To import a file using BULK INSERT, I recommend 1) using a format file and 2) first insert into an intermediary table, because many times we need to polish data, by trimming whitespaces or converting dates. The following is a XML format file.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;?&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;xml&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; version&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;1.0&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;?&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;BCPFORMAT&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; xmlns&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;http://schemas.microsoft.com/sqlserver/2004/bulkload/format&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; xmlns:xsi&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;	&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;RECORD&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;		&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;FIELD&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; ID&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;F1&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; xsi:type&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;CharFixed&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; LENGTH&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;16&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;/&gt;&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;&amp;lt;!-- Fruit name --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;		&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;FIELD&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; ID&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;F2&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; xsi:type&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;CharFixed&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; LENGTH&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;16&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;/&gt;&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;&amp;lt;!-- Family name --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;		&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;FIELD&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; ID&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;F3&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; xsi:type&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;CharFixed&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; LENGTH&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;3&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;/&gt;&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;&amp;lt;!-- Calories --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;		&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;FIELD&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; ID&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;F4&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; xsi:type&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;CharTerm&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; TERMINATOR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;&#92;r&#92;n&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; MAX_LENGTH&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;6&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;/&gt;&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;&amp;lt;!-- Line break --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;	&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;RECORD&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;	&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;ROW&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;		&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;COLUMN&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; SOURCE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;F1&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; NAME&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;FruitName&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; xsi:type&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;SQLVARYCHAR&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; LENGTH&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;16&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; NULLABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;NO&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;		&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;COLUMN&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; SOURCE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;F2&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; NAME&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;FamilyName&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; xsi:type&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;SQLVARYCHAR&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; LENGTH&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;16&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; NULLABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;NO&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;		&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;COLUMN&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; SOURCE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;F3&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; NAME&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;Calories&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; xsi:type&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;SQLINT&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;	&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;ROW&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;BCPFORMAT&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To run a BULK INSERT:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; #temp1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(Fruit &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;16&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), Family &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;16&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;), Calories &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;BULK &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;INSERT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; #temp1 &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;C:&#92;MyFolder&#92;flat_file.txt&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WITH&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  CODEPAGE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;65001&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- UTF-8 with BOM encoding&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  FORMATFILE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;C:&#92;MyFolder&#92;format_file.xml&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  BATCHSIZE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 4000&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- polishing&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;UPDATE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; #temp1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SET&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Fruit] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; TRIM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;([Fruit]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    [Family] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; TRIM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;([Family])&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; *&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; #temp1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;DROP&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; #temp1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Read more on the official docs:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/sql/t-sql/statements/bulk-insert-transact-sql?view=sql-server-ver16&quot;&gt;BULK INSERT command&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/sql/relational-databases/import-export/use-a-format-file-to-bulk-import-data-sql-server?view=sql-server-ver16&quot;&gt;Use a format file to bulk import data&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/sql/relational-databases/import-export/xml-format-files-sql-server?view=sql-server-ver16&quot;&gt;XML Format Files&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Exporting flat files&lt;/h3&gt;&lt;p&gt;Unfortunately, there are no easy ways of generating files straight from the database; for SQL Server, there is only the &lt;em&gt;Import / Export Wizard&lt;/em&gt;, which is a graphical interface inside SSMS.&lt;/p&gt;&lt;p&gt;However, a simple console application could read lines from the database and output a flat file from them.&lt;/p&gt;&lt;br&gt;&lt;h1 id=table-structuring tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#table-structuring class=header-anchor&gt;&lt;span&gt;Table structuring&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;h2 id=primary-key%2C-foreign-key tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#primary-key%2C-foreign-key class=header-anchor&gt;&lt;span&gt;PRIMARY KEY, FOREIGN KEY&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The primary key uniquely identifies each row of a table and determines what is the main search column, structuring the table in a &lt;a href=https://en.wikipedia.org/wiki/B-tree&gt;B-tree&lt;/a&gt;; this makes reading it much faster.&lt;/p&gt;&lt;p&gt;The foreign key is a link between the column of one table to the primary key of another. This increases performance of joins between those tables and is also a form of validation, because a value is only valid if it exists in the foreign table.&lt;/p&gt;&lt;p&gt;Taking the initial example:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Fruit](&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [Id] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NOT NULL&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; IDENTITY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;PRIMARY KEY&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; CLUSTERED&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;64&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NOT NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [IdFamily] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NOT NULL&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; FOREIGN KEY&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; REFERENCES&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Family](Id),&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [Calories] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NOT NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=indexes tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#indexes class=header-anchor&gt;&lt;span&gt;INDEXES&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;They are additional search rails on a table that run parallel to the primary key. They are useful for tables with more than one search criteria.&lt;/p&gt;&lt;p&gt;Imagine a Person table, with columns Id, NationalIdentifier and Name: it&#39;s common to search a person by its national identifier or name, but, these columns are not the primary key, which makes searching by them slower. In these cases, the search is done individually line by line, over the whole table; moreover, it&#39;s a textual comparison, because NationalIdentifier and Name are texts. Textual comparisons are slower than numerical comparisons, which is the case of Id.&lt;/p&gt;&lt;p&gt;To speed the search, we can create indexes. The most common type is the &lt;em&gt;hash index&lt;/em&gt;, which attributes a random number to each indexed value and saves this number next to the record. Whenever a search comes to use this criterion, the comparison will be numerical and with better performance than checking the field&#39;s value on every line.&lt;/p&gt;&lt;p&gt;Index creation:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- one column&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; INDEX&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; IX_Person_NationalIdentifier&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ON&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Person]([NationalIdentifier]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- more than one column&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; INDEX&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; IX_Address_CityStateCountry&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;ON&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Address]([City],[State],[Country]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=unique tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#unique class=header-anchor&gt;&lt;span&gt;UNIQUE&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;It&#39;s a special type of constraint that blocks repeated values in a column. In most databases, creating an unique constraint also creates an index for this column.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Person] (  &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  Id &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NOT NULL&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; PRIMARY KEY&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; CLUSTERED&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  NationalIdentifier &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;CHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;11&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NOT NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;64&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NOT NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;  CONSTRAINT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; CT_Unique_Person_NationalIdentifier &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;UNIQUE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;([NationalIdentifier])&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=sparse tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#sparse class=header-anchor&gt;&lt;span&gt;SPARSE&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Sparse is a column modifier that optimizes storage when there are many null values.&lt;/p&gt;&lt;p&gt;In traditional storage, a field has a reserved amount of bytes for it in the row even when the value is null, which is a waste.&lt;/p&gt;&lt;p&gt;With sparse columns, a null value occupies zero bytes on the row and a non-null value occupies the original size plus 4 bytes.&lt;/p&gt;&lt;p&gt;Practical example, &lt;code&gt;NVARCHAR(16)&lt;/code&gt; column needs 32 bytes on each row. With sparse, if null, 0 bytes will be used; if not null, 36 bytes.&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Percentage of nulls&lt;/th&gt;&lt;th style=text-align:center&gt;Column size difference&lt;br&gt;with SPARSE&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;0%&lt;/td&gt;&lt;td style=text-align:center&gt;+12.5%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;25%&lt;/td&gt;&lt;td style=text-align:center&gt;-15.6%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;75%&lt;/td&gt;&lt;td style=text-align:center&gt;-71.9%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Formula: &lt;code&gt;1 - ((T+4)/T) * (1-N)&lt;/code&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;T&lt;/strong&gt; : original field size&lt;/li&gt;&lt;li&gt;&lt;strong&gt;N&lt;/strong&gt; : percentage of nulls&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If there are not many nulls, there is no advantage in using sparse columns, but they save space if the percentage of nullability is high.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Person] (  &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  Id &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NOT NULL&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; PRIMARY KEY&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; CLUSTERED&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  NationalIdentifier &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;CHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;11&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NOT NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  [Name] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;64&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NOT NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  FavouriteColour &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;32&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) SPARSE &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=columnstore tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#columnstore class=header-anchor&gt;&lt;span&gt;COLUMNSTORE&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;em&gt;Columnstore&lt;/em&gt; is a storage strategy.&lt;/p&gt;&lt;p&gt;The default storage mode of a table is linear, with rows laid inside pages. A, B and C are columns:&lt;/p&gt;&lt;pre&gt;&lt;code class=language-mermaid&gt;&lt;div class=mermaid&gt;flowchart TB
  subgraph page[Page]
    direction LR
    subgraph row1[Row 1]
      direction TB
      A1
      B1
      C1
    end
    subgraph row2[Row 2]
      direction TB
      A2
      B2
      C2
    end    
    subgraph row3[Row 3]
      direction TB
      A3
      B3
      C3
    end
end
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With columnar storage, a page is exclusive for a column:&lt;/p&gt;&lt;pre&gt;&lt;code class=language-mermaid&gt;&lt;div class=mermaid&gt;flowchart TB
  subgraph pageC[Page]
    subgraph columnC[Column C]
      direction LR
      C1
      C2
      C3
    end
  end
  subgraph pageB[Page]
    subgraph columnB[Column B]
      direction LR
      B1
      B2
      B3
    end
  end  
  subgraph pageA[Page]
    subgraph columnA[Column A]
      direction LR
      A1
      A2
      A3
    end
  end
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What is the advantage of this approach? Columnar storage has compression by default and if values frequently repeat in columns, the storage size can be greatly reduced.&lt;/p&gt;&lt;p&gt;See below how columnar compression works:&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=text-align:center&gt;Uncompressed column&lt;/th&gt;&lt;th style=text-align:center&gt;Compressed column&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;A&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;5 x A&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;A&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;2 x B&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;A&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;3 x A&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;A&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;A&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;B&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;B&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;A&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;A&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=text-align:center&gt;A&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;According to SQL Server &lt;a href=&quot;https://learn.microsoft.com/en-us/sql/relational-databases/indexes/columnstore-indexes-overview?view=sql-server-ver16&quot;&gt;docs&lt;/a&gt;, the storage size can be up to 10x smaller and the reading speed up to 10x higher, compared to a linear storage.&lt;/p&gt;&lt;h3&gt;When to use columnstore&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;High number of repetitions of values in vertical directions.&lt;/li&gt;&lt;li&gt;Low cardinality (possible variations of values).&lt;/li&gt;&lt;li&gt;High volume of data (over 500k lines).&lt;/li&gt;&lt;li&gt;Analytical processes: sums, averages, counts.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;When not to use columnstore&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Records that have many updates and deletes, because compression is lost when there are changes.&lt;/li&gt;&lt;li&gt;Records that are entities, because &lt;strong&gt;columnstore tables have no primary keys&lt;/strong&gt;.&lt;/li&gt;&lt;li&gt;If this table is used for many joins.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Clustered vs nonclustered&lt;/h3&gt;&lt;p&gt;A &lt;strong&gt;clustered&lt;/strong&gt; columnstore index is when the table uses columnar storage. A &lt;strong&gt;nonclustered&lt;/strong&gt; columnstore index is when the table uses linear storage and columnstore is an auxiliary index; this is an option when you want the benefits of columnstore (analytical performance) without losing the benefits of linear tables (primary keys).&lt;/p&gt;&lt;h3&gt;Table creation&lt;/h3&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; TABLE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[EntryFruitFile](&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;	Fruit &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;16&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NOT NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;	Family &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;16&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NOT NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;	Calories &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NOT NULL&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;	INDEX&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; CCI_EntryFruitFile &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CLUSTERED&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; COLUMNSTORE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br&gt;&lt;h1 id=special tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#special class=header-anchor&gt;&lt;span&gt;Special&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;h2 id=import-dlls tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#import-dlls class=header-anchor&gt;&lt;span&gt;IMPORT DLLs&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Yes, it is possible to import DLLs to execute on SQL Server.&lt;/p&gt;&lt;p&gt;Custom DLLs are interesting for use cases where there is no native similar, like: read and write files; HTTP calls; generate and validate hashes.&lt;/p&gt;&lt;p&gt;DLLs must be .NET Framework source code and signed with a strong name.&lt;/p&gt;&lt;p&gt;The process is a bit complex and the steps here are based on &lt;a href=https://www.c-sharpcorner.com/article/assembly-in-ms-sql-server/ &gt;this article&lt;/a&gt; from C-Sharp Corner.:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Create a Class Library project in .NET Framework&lt;/li&gt;&lt;li&gt;C# code example below:&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; System&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;namespace&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; MyDotnetSqlProj&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; static&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; class&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Class1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;        public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; static&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; double&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; CalculateHypotenuse&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;double&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; side1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;double&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; side2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;            Math&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Sqrt&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Math&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Pow&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;side1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;+&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; Math&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Pow&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;side2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=3&gt;&lt;li&gt;On Visual Studio, click with the mouse right button on the project, &lt;em&gt;Properties&lt;/em&gt;, &lt;em&gt;Signing&lt;/em&gt;, check &lt;strong&gt;Sign the assembly&lt;/strong&gt;. Choose or make a new strong name key file. If you are creating, you can uncheck &lt;em&gt;Protect my key file with a password&lt;/em&gt;.&lt;/li&gt;&lt;li&gt;Build the project.&lt;/li&gt;&lt;li&gt;Now, we must import the assymetric signing key, create a login in the &lt;code&gt;master&lt;/code&gt; database and concede UNSAFE ASSEMBLY permission to it:&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;USE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [master]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ASYMMETRIC&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; KEY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; AssymetricKey1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; EXECUTABLE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FILE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;C:&#92;Projects&#92;MyDotnetSqlProj&#92;bin&#92;Debug&#92;MyDotnetSqlProj.dll&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; LOGIN&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; LoginAssymetricKey1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ASYMMETRIC&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; KEY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; AssymetricKey1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GRANT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; UNSAFE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ASSEMBLY&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; TO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; LoginAssymetricKey1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=6&gt;&lt;li&gt;In the application database, create an user for the recently created login, import the assembly and enable CLR execution:&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;USE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [YourDB];&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; USER&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; UserLoginAssymetricKey1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FOR&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; LOGIN&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; LoginAssymetricKey1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ASSEMBLY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; AssemblyMyLib&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;C:&#92;Projects&#92;MyDotnetSqlProj&#92;bin&#92;Debug&#92;MyDotnetSqlProj.dll&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WITH&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; PERMISSION_SET&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; SAFE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;sp_configure &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;clr enabled&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;RECONFIGURE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=7&gt;&lt;li&gt;Let&#39;s create a FUNCTION that calls the DLL&#39;s code:&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;USE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [YourDB];&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- for string, use NVARCHAR parameters&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FUNCTION&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[CalculateHypotenuse] (@side1 &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FLOAT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, @side2 &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FLOAT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;RETURNS&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FLOAT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  EXTERNAL&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; NAME&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [AssemblyMyLib].[MyDotnetSqlProj.Class1].[CalculateHypotenuse];&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=8&gt;&lt;li&gt;To execute the function:&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- returns 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[CalculateHypotenuse] (&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;0&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;4&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;0&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;as&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Hypotenuse];&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- returns 13&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[CalculateHypotenuse] (&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;5&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;0&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;12&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;0&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;as&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Hypotenuse];&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=json tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#json class=header-anchor&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;To handle JSONs inside the database.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;DECLARE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @json &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NVARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;100&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;{&quot;cities&quot;: [&quot;Aracaju&quot;, &quot;João Pessoa&quot;, &quot;Maceió&quot;]}&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- returns 3 lines with the cities&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; *&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FROM&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; OPENJSON&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(@json, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;$.cities&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;-- returns 1 line with the selected city&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; JSON_VALUE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(@json, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;$.cities[1]&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Check more in the &lt;a href=&quot;https://learn.microsoft.com/en-us/sql/relational-databases/json/json-data-sql-server?view=sql-server-ver16&quot;&gt;docs&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=applocks tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#applocks class=header-anchor&gt;&lt;span&gt;APPLOCKS&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;They are application locks inside the database. They are different from row locks.&lt;/p&gt;&lt;p&gt;Can be used for concurrency control, such as for reading messages with multiple simultaneous consumers.&lt;/p&gt;&lt;p&gt;The SQL Server functions are &lt;code&gt;sp_getapplock&lt;/code&gt; and &lt;code&gt;sp_releaseapplock&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Learn more in the article about &lt;a href=https://alexandrehtrb.github.io/posts/2024/06/asynchronous-architecture-without-queues/#messages-in-databases&gt;asynchronous architecture without queues&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=view-execution-plan tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#view-execution-plan class=header-anchor&gt;&lt;span&gt;VIEW EXECUTION PLAN&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The execution plan describes which steps the database engine needs to perform to execute a command or query.&lt;/p&gt;&lt;p&gt;On SSMS, enabling the &lt;em&gt;Include execution plan&lt;/em&gt; on the top menu will include the plan along with query results.&lt;/p&gt;&lt;p&gt;By analyzing the cost of each step, you can understand which performance bottlenecks exist and from there improve your query, by creating indexes, rewriting WHERE and JOIN criteria, and others.&lt;/p&gt;&lt;img alt=&quot;SQL execution plan&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_08_sql_execution_plan.jpg class=my-4&gt;&lt;br&gt;&lt;h1 id=final-conclusions tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/08/sql-iceberg/#final-conclusions class=header-anchor&gt;&lt;span&gt;Final conclusions&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;img alt=&quot;Jack and Rose on the Titanic&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_08_titanic.jpg class=my-4&gt;&lt;p&gt;SQL is an extremely powerful and complete tool, and acquired new capabilities over the years. It is no wonder that remains being the mainstream for databases up to today; it is the basis for complex systems.&lt;/p&gt;&lt;p&gt;This article covered common and less known SQL features, and still there are many others that could be addressed here with real world applications, therefore, it is worth it to explore the documentation of your database, because for many times it has the answer for a challenge you might be facing.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Shiki and Mermaid in 11ty</title>
    <link href="https://alexandrehtrb.github.io/posts/2024/07/shiki-and-mermaid-in-11ty/" />
    <updated>2024-07-16T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2024/07/shiki-and-mermaid-in-11ty/</id>
    <content type="html">&lt;h2 id=11ty%2C-shiki-and-mermaid tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/07/shiki-and-mermaid-in-11ty/#11ty%2C-shiki-and-mermaid class=header-anchor&gt;&lt;span&gt;11ty, Shiki and Mermaid&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;a href=https://www.11ty.dev/ &gt;11ty&lt;/a&gt; (Eleventy) is a static-site generator tool that uses templating engines to generate websites. Eleventy has a pipeline execution that makes it easy to add plugins and transformations to HTML, JS and CSS files.&lt;/p&gt;&lt;p&gt;&lt;a href=https://shiki.style/ &gt;Shiki&lt;/a&gt; is a npm package that renders HTML code blocks with syntax highlighting for a specified language. Among its interesting features, it allows dual theming (light and dark switching), code focusing and diffing notations, and custom themes.&lt;/p&gt;&lt;p&gt;While I was making this blog, which uses 11ty, I wanted to have support for &lt;a href=https://mermaid.js.org&gt;Mermaid&lt;/a&gt; diagrams in my blog posts, alongside code blocks. In this post, let&#39;s see how to integrate Shiki and Mermaid into your 11ty project.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/07/shiki-and-mermaid-in-11ty/#shiki-integration&gt;Shiki integration&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/07/shiki-and-mermaid-in-11ty/#mermaid-integration&gt;Mermaid integration&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/07/shiki-and-mermaid-in-11ty/#final-results&gt;Final results&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/07/shiki-and-mermaid-in-11ty/#copy-code-buttons&gt;Copy code buttons&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=shiki-integration tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/07/shiki-and-mermaid-in-11ty/#shiki-integration class=header-anchor&gt;&lt;span&gt;Shiki integration&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;h3&gt;Add Shiki to your project&lt;/h3&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;npm&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; install&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -D&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; shiki&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Shiki custom plug-in&lt;/h3&gt;&lt;p&gt;Create a Javascript file to configure Shiki for your project, for example, at &lt;code&gt;./shiki.config.mjs&lt;/code&gt; (let&#39;s make it using ES Modules). The &lt;code&gt;highlighter&lt;/code&gt; ideally should be used as a singleton.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;import&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; { &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;createHighlighter&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; } &lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;from&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;shiki&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;export&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; default&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; function&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;options&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  // empty call to notify 11ty that we use this feature&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  // eslint-disable-next-line no-empty-function&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;  eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;amendLibrary&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;md&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, () &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;=&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; { });&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;  eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;on&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;eleventy.before&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;async&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; () &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;=&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;    const&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt; highlighter&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; await&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; createHighlighter&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;      themes:&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;light-plus&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;dark-plus&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;      langs:&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;html&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;sql&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;xml&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;javascript&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;amendLibrary&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;md&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;mdLib&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;      mdLib&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;set&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;        highlight&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;:&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;code&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;lang&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;=&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;          return&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; highlighter&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;codeToHtml&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;code&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;          {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;            lang:&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; lang&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;            themes:&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;              light:&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;light-plus&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;              dark:&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;dark-plus&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;          });&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;      })&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Call Shiki custom plug-in in &lt;code&gt;eleventy.config.mjs&lt;/code&gt;&lt;/h3&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes has-diff&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;import&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; shikiPlugin&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; from&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;./shiki.config.mjs&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;export&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; default&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; function&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  // replace 11ty default syntax highlight plugin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff remove&quot;&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;  eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;addPlugin&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;syntaxHighlight&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;  eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;addPlugin&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;shikiPlugin&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;); &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=mermaid-integration tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/07/shiki-and-mermaid-in-11ty/#mermaid-integration class=header-anchor&gt;&lt;span&gt;Mermaid integration&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;If you want to use Shiki and also want to render Mermaid diagrams, you need to change the Shiki plug-in to render Mermaid as HTML divs, instead of code blocks.&lt;/p&gt;&lt;h3&gt;Add htmlencode to your project&lt;/h3&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;npm&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; install&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -D&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; htmlencode&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Modify Shiki plug-in&lt;/h3&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes has-diff&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;import&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; { &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;createHighlighter&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; } &lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;from&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;shiki&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;import&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; htmlencode&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; from&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;htmlencode&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;export&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; default&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; function&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;options&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  // empty call to notify 11ty that we use this feature&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  // eslint-disable-next-line no-empty-function&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;  eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;amendLibrary&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;md&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, () &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;=&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; { });&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;  eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;on&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;eleventy.before&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;async&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; () &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;=&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;    const&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt; highlighter&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; await&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; createHighlighter&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;      themes:&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;light-plus&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;dark-plus&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;      langs:&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;html&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;sql&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;xml&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;javascript&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;amendLibrary&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;md&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;mdLib&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;      mdLib&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;set&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;        highlight&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;:&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;code&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;lang&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;=&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;          if&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;lang&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; ===&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;mermaid&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) { &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;            const&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt; extra_classes&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; options&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;?.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;extra_classes&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; ?&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39; &#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; +&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; options&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;extra_classes&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; :&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;            return&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; `&amp;lt;div class=&quot;mermaid&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A73A1&gt;${&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;extra_classes&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A73A1&gt;}&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;&gt;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A73A1&gt;${&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;htmlencode&lt;/span&gt;&lt;span style=color:#000000FF;--shiki-dark:#AFAC7C&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;htmlEncode&lt;/span&gt;&lt;span style=color:#000000FF;--shiki-dark:#AFAC7C&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;code&lt;/span&gt;&lt;span style=color:#000000FF;--shiki-dark:#AFAC7C&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A73A1&gt;}&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&amp;lt;/div&gt;`&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;          } &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;          else&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; { &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;            return&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; highlighter&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;codeToHtml&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;code&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;              lang:&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; lang&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;              themes:&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;                light:&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;light-plus&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;                dark:&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;dark-plus&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;              }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;            });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;          } &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;      })&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Mermaid custom plug-in&lt;/h3&gt;&lt;p&gt;Create a Javascript file to configure Mermaid for your project, for example, at &lt;code&gt;./mermaid.config.mjs&lt;/code&gt; (let&#39;s make it using ES Modules):&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;export&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; default&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;options&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;=&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;  let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; mermaid_config&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;    startOnLoad:&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; false&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;    theme:&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;default&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#71B0D3&gt;    loadOnSave:&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;  let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; src&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; options&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;?.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;mermaid_js_src&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; ||&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;https://unpkg.com/mermaid/dist/mermaid.esm.min.mjs&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;  eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;addShortcode&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;mermaid_js_scripts&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, () &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;=&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;    return&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; `&amp;lt;script type=&quot;module&quot; async&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;              import mermaid from &quot;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A73A1&gt;${&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;src&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A73A1&gt;}&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;              const config = &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A73A1&gt;${&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt;JSON&lt;/span&gt;&lt;span style=color:#000000FF;--shiki-dark:#AFAC7C&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;stringify&lt;/span&gt;&lt;span style=color:#000000FF;--shiki-dark:#AFAC7C&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;mermaid_config&lt;/span&gt;&lt;span style=color:#000000FF;--shiki-dark:#AFAC7C&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A73A1&gt;}&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;              mermaid.initialize(config);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;              await mermaid.run({&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;                querySelector: &#39;.mermaid&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;              });&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;            &amp;lt;/script&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;  return&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Call Mermaid custom plug-in in &lt;code&gt;eleventy.config.mjs&lt;/code&gt;&lt;/h3&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes has-diff&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;import&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; shikiPlugin&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; from&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;./shiki.config.mjs&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;import&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; mermaidPlugin&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; from&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;./mermaid.config.mjs&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;export&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; default&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; function&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;  eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;addPlugin&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;shikiPlugin&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;  eleventyConfig&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;addPlugin&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;mermaidPlugin&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;); &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Include Mermaid script in pages&lt;/h3&gt;&lt;p&gt;Add the &lt;code&gt;mermaid_js_scripts&lt;/code&gt; shortcode to pages and templates that will have diagrams:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;{% mermaid_js_scripts %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=final-results tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/07/shiki-and-mermaid-in-11ty/#final-results class=header-anchor&gt;&lt;span&gt;Final results&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Let&#39;s see it working.&lt;/p&gt;&lt;p&gt;SQL code block with syntax highlight:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; *&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; INTO&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; dbo.NewProducts&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Production.Product&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; ListPrice &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;&gt;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 25&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AND&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; ListPrice &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 100&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Mermaid flowchart:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;flowchart TD&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;    A[Christmas] --&gt;|Get money| B(Go shopping)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;    B --&gt; C{Let me think}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;    C --&gt;|One| D[Laptop]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;    C --&gt;|Two| E[iPhone]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;    C --&gt;|Three| F[fa:fa-car Car]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=language-mermaid&gt;&lt;div class=mermaid&gt;flowchart TD
    A[Christmas] --&gt;|Get money| B(Go shopping)
    B --&gt; C{Let me think}
    C --&gt;|One| D[Laptop]
    C --&gt;|Two| E[iPhone]
    C --&gt;|Three| F[fa:fa-car Car]
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you want to check a full source code example for this blog project, visit our &lt;a href=https://github.com/alexandrehtrb/alexandrehtrb.github.io&gt;GitHub repo&lt;/a&gt;. It includes switching between light and dark themes for both Shiki and Mermaid.&lt;/p&gt;&lt;h2 id=copy-code-buttons tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/07/shiki-and-mermaid-in-11ty/#copy-code-buttons class=header-anchor&gt;&lt;span&gt;Copy code buttons&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Shiki doesn&#39;t provide copy code buttons by default, but we can add them through a client-side script. I use a slightly modified version of the script shown in &lt;a href=https://junges.dev/2-how-to-add-github-copy-to-clipboard-button-on-your-docsblog&gt;this blog post&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;Reference the script in templates&lt;/h3&gt;&lt;p&gt;Add the &lt;code&gt;&amp;lt;script&gt;&lt;/code&gt; tag below to templates and HTML files:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;script&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; src&lt;/span&gt;&lt;span style=color:#000000FF;--shiki-dark:#AFAC7C&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;/assets/scripts/addCopyCodeButtons.js&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;script&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Add script to insert copy code buttons&lt;/h3&gt;&lt;p&gt;Create a Javascript file for a client-side script that will find all code blocks and add copy code buttons to them. The icons SVGs are declared inline in this example.&lt;/p&gt;&lt;p&gt;For example, create your file at &lt;code&gt;src/scripts/addCopyCodeButtons.js&lt;/code&gt;:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; blocks&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; document&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;querySelectorAll&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;pre.shiki&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;const&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt; copyCodeIconSvg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;&amp;lt;svg height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot;&gt;&amp;lt;path fill=&quot;#666666&quot; d=&quot;M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z&quot;&gt;&amp;lt;/path&gt;&amp;lt;path fill=&quot;#666666&quot; d=&quot;M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z&quot;&gt;&amp;lt;/path&gt;&amp;lt;/svg&gt;&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;const&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt; codeCopiedIconSvg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;&amp;lt;svg height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; version=&quot;1.1&quot; width=&quot;16&quot;&gt;&amp;lt;path fill=&quot;#28D751&quot; d=&quot;M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z&quot;&gt;&amp;lt;/path&gt;&amp;lt;/svg&gt;&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;blocks&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;forEach&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;((&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;block&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;=&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;    if&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;!&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;navigator&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;clipboard&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;        return&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; button&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; document&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;createElement&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;button&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    button&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;className&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;button-copy-code&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    button&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;ariaLabel&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; button&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;title&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;Copy&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    button&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;innerHTML&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; copyCodeIconSvg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    block&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;appendChild&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;button&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    button&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;addEventListener&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;click&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;async&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; () &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;=&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;        await&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; copyCode&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;button&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;block&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;async&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; function&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; copyCode&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;button&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;block&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; copiedCode&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; block&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;cloneNode&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt;true&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    copiedCode&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;removeChild&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;copiedCode&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;querySelector&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;button.button-copy-code&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;    const&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt; html&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; copiedCode&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;outerHTML&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;replace&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#811f3f;--shiki-dark:#9C4444&gt;/&amp;lt;&lt;/span&gt;&lt;span style=color:#d16969;--shiki-dark:#AC6E56&gt;[^&lt;/span&gt;&lt;span style=color:#811f3f;--shiki-dark:#AD4F4F&gt;&gt;&lt;/span&gt;&lt;span style=color:#d16969;--shiki-dark:#AC6E56&gt;]&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#AF955D&gt;*&lt;/span&gt;&lt;span style=color:#811f3f;--shiki-dark:#9C4444&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#AF955D&gt;?&lt;/span&gt;&lt;span style=color:#811f3f;--shiki-dark:#9C4444&gt;/&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;gm&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    block&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;querySelector&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;button.button-copy-code&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;).&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;innerHTML&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; codeCopiedIconSvg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    button&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;ariaLabel&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; button&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;title&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;Copied!&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;    setTimeout&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;function&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;        block&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;querySelector&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;button.button-copy-code&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;).&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;innerHTML&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; copyCodeIconSvg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;        button&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;ariaLabel&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; button&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;title&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;Copy&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    }, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;2000&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;    const&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt; parsedHTML&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; htmlDecode&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;html&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;    await&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; navigator&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;clipboard&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;writeText&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;parsedHTML&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;function&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; htmlDecode&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;input&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;    const&lt;/span&gt;&lt;span style=color:#0070c1;--shiki-dark:#65A5C7&gt; doc&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt; new&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; DOMParser&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;().&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;parseFromString&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;input&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;text/html&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;    return&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; doc&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;documentElement&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;textContent&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;CSS for copy code buttons&lt;/h3&gt;&lt;p&gt;Add the CSS code below to style the button position and visibility:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#998558&gt;pre&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;[&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt;class&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;*=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;shiki&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#e50000;--shiki-dark:#62A6CA&gt;  position&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#0451a5;--shiki-dark:#AD7159&gt;relative&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#e50000;--shiki-dark:#62A6CA&gt;  margin&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;5&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#85A574&gt;px&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 0&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#e50000;--shiki-dark:#62A6CA&gt;  padding&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1.75&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#85A574&gt;rem&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 0&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1.75&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#85A574&gt;rem&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#85A574&gt;rem&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#998558&gt;pre&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; &gt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#B69D69&gt; .button-copy-code&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#e50000;--shiki-dark:#62A6CA&gt;  position&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#0451a5;--shiki-dark:#AD7159&gt;absolute&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#e50000;--shiki-dark:#62A6CA&gt;  top&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;32&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#85A574&gt;px&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#e50000;--shiki-dark:#62A6CA&gt;  right&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;16&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#85A574&gt;px&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;@media&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; only&lt;/span&gt;&lt;span style=color:#0451a5;--shiki-dark:#AD7159&gt; screen&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; and&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#62A6CA&gt;max-device-width&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;480&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#85A574&gt;px&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#998558&gt;  pre&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; &gt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#B69D69&gt; .button-copy-code&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#e50000;--shiki-dark:#62A6CA&gt;    display&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#0451a5;--shiki-dark:#AD7159&gt;none&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=references tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/07/shiki-and-mermaid-in-11ty/#references class=header-anchor&gt;&lt;span&gt;References&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://www.11ty.dev/docs/ &gt;11ty docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://shiki.style/guide/ &gt;Shiki docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://mermaid.js.org/intro/ &gt;Mermaid docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://junges.dev/2-how-to-add-github-copy-to-clipboard-button-on-your-docsblog&gt;Junges.dev - How to add GitHub Copy to Clipboard button on your docs/blog&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Asynchronous architecture without queues</title>
    <link href="https://alexandrehtrb.github.io/posts/2024/06/asynchronous-architecture-without-queues/" />
    <updated>2024-06-24T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2024/06/asynchronous-architecture-without-queues/</id>
    <content type="html">&lt;img alt=&quot;People in a queue to buy tickets for Paul McCartney concert&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2024_06_fila_ingressos_paul_mccartney.jpg&gt;&lt;h2 id=asynchronous-architecture tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/asynchronous-architecture-without-queues/#asynchronous-architecture class=header-anchor&gt;&lt;span&gt;Asynchronous architecture&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;A common strategy in complex systems is asynchronism, which is leaving heavier tasks running on background and getting a return from them only when they are finished. The idea is to deliver an immediate response to the user, allowing him / her to do other activities in the meanwhile. This approach exists both in programming languages, by the use of the &lt;code&gt;async / await&lt;/code&gt; keywords, and in systems architectures, with an event or message oriented processing.&lt;/p&gt;&lt;p&gt;There are dedicated queues that are very popular today, among them, Apache Kafka and RabbitMQ, that are used for asynchronous processing. They can handle high volumes of messages received and processed in parallel, taking care of concurrency and post-processing confirmation.&lt;/p&gt;&lt;p&gt;Despite the popularity of those queues, other lighter and more practical alternatives can be used in substitution, solving the same problems in a simpler and even cheaper way. Let&#39;s see them.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/asynchronous-architecture-without-queues/#messages-in-databases&gt;Messages in databases&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/asynchronous-architecture-without-queues/#messages-in-distributed-caches&gt;Messages in distributed caches&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/asynchronous-architecture-without-queues/#parallel-threads&gt;Parallel threads&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=messages-in-databases tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/asynchronous-architecture-without-queues/#messages-in-databases class=header-anchor&gt;&lt;span&gt;Messages in databases&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Here, a database stores the messages. There is an application that inserts messages in the database (publisher) and another that reads them (consumer).&lt;/p&gt;&lt;p&gt;In this case, messages are persisted and there is no risk of losing them due to reinitializations. Both SQL and NoSQL databases can be used.&lt;/p&gt;&lt;p&gt;For example, we can have a SQL table that contains the messages:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;| Id |      Status      | Content  |&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;|----|------------------|----------|&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;|  1 | Processed        |   msg1   |&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;|  2 | Processed        |   msg2   |&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;|  3 | ProcessingFailed |   msg3   |&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;|  4 | InProcess        |   msg4   |&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;|  5 | Waiting          |   msg5   |&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;|  6 | Waiting          |   msg6   |&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;Status&lt;/code&gt; column describes which message already were processed and which are waiting. At least four status need to exist:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Waiting processing&lt;/li&gt;&lt;li&gt;In process&lt;/li&gt;&lt;li&gt;Processing failed&lt;/li&gt;&lt;li&gt;Processed&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The &lt;em&gt;ProcessingFailed&lt;/em&gt; status is very important, because it allows developers to analyse the failed messages for possible bugs at the processing, and to identify messages that come invalid or malformatted.&lt;/p&gt;&lt;p&gt;Here, if there is more than one simultaneous consumer, we must prepare against concurrency issues, to avoid that a message be processed more than once. The solution for this is a lock.&lt;/p&gt;&lt;h3&gt;Database locks&lt;/h3&gt;&lt;p&gt;A lock (mutex) restrains access for only the transaction that detains this lock.&lt;/p&gt;&lt;p&gt;When a consumer goes to take the next message for processing, it should lock for reading, to block other consumers from taking this same message at the same time. If a consumer cannot open the lock, it is because another consumer arrived earlier, which means that it should wait until the lock is released.&lt;/p&gt;&lt;p&gt;During the locking, the message is retrieved and marked as &lt;em&gt;InProcess&lt;/em&gt;, and after that, the reading is unlocked for other consumers.&lt;/p&gt;&lt;p&gt;This technique exists in many databases:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;SQL Server&lt;/strong&gt;: &lt;code&gt;sp_getapplock&lt;/code&gt; with &lt;code&gt;sp_releaseapplock&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt;: &lt;code&gt;pg_advisory_xact_lock()&lt;/code&gt; with &lt;code&gt;SET LOCAL lock_timeout = &#39;4s&#39;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;MongoDB&lt;/strong&gt;: &lt;code&gt;db.coll.findAndModify()&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The code below is a SQL Server stored procedure that takes the next message to be consumed using an app lock.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;CREATE&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; OR&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ALTER&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; PROCEDURE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; TakeMessageToProcess&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    @status &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;VARCHAR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;30&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;AS&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;BEGIN&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; TRANSACTION&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    DECLARE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @res &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    -- locking for reading&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    EXEC&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @res &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; sp_getapplock                 &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;         @Resource &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;TAKE_MESSAGE_LOCK&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;         @LockMode &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;Exclusive&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;         @LockOwner &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;Transaction&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;         @LockTimeout &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 60000&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;         @DbPrincipal &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;public&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    -- verifying that the lock was obtained&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    IF&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @res &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;NOT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; IN&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;0&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    BEGIN&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        RAISERROR&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&#39;Unable to get lock.&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;16&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    END&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    ELSE&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    BEGIN&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;      -- taking a message with the desired status&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;      DECLARE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @msgId &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;INT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SELECT&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; TOP&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Id] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Messages] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Status] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @status);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;      -- marking message status as &#39;InProcess&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;      UPDATE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Messages] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;SET&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Status] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;InProcess&#39;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Id] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @msgId;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;      -- returning the message for consumer&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;      SELECT&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; *&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; FROM&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [dbo].[Messages] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;WHERE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; [Id] &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @msgId;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;      -- releasing the lock after reading&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;      EXEC&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; @res &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; sp_releaseapplock &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;           @Resource &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;TAKE_MESSAGE_LOCK&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;           @DbPrincipal &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;public&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;           @LockOwner &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;Transaction&#39;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    END&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;COMMIT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;GO&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The consumer must execute the SQL command:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;EXECUTE&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; TakeMessageToProcess @status &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &#39;Waiting&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Invocation&lt;/h3&gt;&lt;p&gt;The database cannot proactively invoke a consumer, alerting it that there is a new message to be processed. Therefore, other triggers must be used, such as the consumer periodically checking for new messages; or cron jobs, that schedule the consumer for execution on certain times of the day.&lt;/p&gt;&lt;h2 id=messages-in-distributed-caches tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/asynchronous-architecture-without-queues/#messages-in-distributed-caches class=header-anchor&gt;&lt;span&gt;Messages in distributed caches&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Distributed caches, like Redis, can store messages, holding them inside key-value pairs, queues, or other data structures.&lt;/p&gt;&lt;p&gt;This implementation can be considered a variation of the one above.&lt;/p&gt;&lt;p&gt;An advantage is that Redis already has native queues, saving development effort.&lt;/p&gt;&lt;p&gt;However, a disadvantage is that messages can be lost in case of a reinitialization of the cache, since there is no persistence (due to being a volatile storage).&lt;/p&gt;&lt;p&gt;Example of a queue using Redis commands:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;# inserts at the end of the queue&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;LPUSH&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; my_queue&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;Task1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;# inserts at the end of the queue&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;LPUSH&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; my_queue&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;Task2&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;# pops the head of the queue: &quot;Task1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;RPOP&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; my_queue&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;# pops the head of the line: &quot;Task2&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;RPOP&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; my_queue&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Distributed locks&lt;/h3&gt;&lt;p&gt;Distributed caches can provide locks to prevent read concurrencies. Redis documentation details how to implement a distributed lock in a safe way and considering multiple consumers.&lt;/p&gt;&lt;h2 id=parallel-threads tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/asynchronous-architecture-without-queues/#parallel-threads class=header-anchor&gt;&lt;span&gt;Parallel threads&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;This option is very practical when you want to condense the processing in a single application — it produces and consumes the message internally, in separate threads.&lt;/p&gt;&lt;p&gt;The communication between production and consumption threads is through thread-safe concurrent queues, like channels, in .NET, or ConcurrentLinkedQueue, in Java. The consumption thread must run indefinitely in background, processing messages as they arrive in the queue.&lt;/p&gt;&lt;p&gt;Some real life scenarios in which this option may be appropriate:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;User registration&lt;/strong&gt;: an API receives a call for user registration, which involves many substeps, such as identity verification, anti-fraud prevention and sending a confirmation email. These substeps may be light enough to not need to be run in a separate application.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Logs and metrics&lt;/strong&gt;: in most programs, logs and metrics are sent to their servers in background threads.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We must take into account that this processing implies higher CPU and RAM usage on the application and may compete with other tasks for resources. Solutions for that are vertical scaling (increase available CPU and RAM) and horizontal scaling (distribute the load among other instances).&lt;/p&gt;&lt;h3&gt;Practical example&lt;/h3&gt;&lt;p&gt;The code below is an ASP.NET minimal API that uses channels to process messages, that are received on an HTTP endpoint and handled by a &lt;code&gt;MyMessageProcessor&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;To run the program below:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Have the &lt;a href=https://dotnet.microsoft.com/ &gt;.NET SDK&lt;/a&gt; installed on your machine&lt;/li&gt;&lt;li&gt;Create a minimal API project:&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;# command-line&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;mkdir&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; MyChannelsAPI&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;cd&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; ./MyChannelsAPI/&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;dotnet&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; new&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; web&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=3&gt;&lt;li&gt;Copy the code below and paste it in the &lt;code&gt;Program.cs&lt;/code&gt; file&lt;/li&gt;&lt;li&gt;Run the project, &lt;code&gt;dotnet run&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; System&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Threading&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Channels&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#417EB1&gt;using&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Microsoft&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;AspNetCore&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;Mvc&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;var&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; builder&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; WebApplication&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;CreateBuilder&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;args&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// creating the channel and the processor&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;var&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; channel&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; Channel&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;CreateUnbounded&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;MyMessage&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;builder&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Services&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;AddSingleton&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;ChannelWriter&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;MyMessage&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt;&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;channel&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Writer&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;builder&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Services&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;AddSingleton&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;ChannelReader&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;MyMessage&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt;&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;channel&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Reader&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;builder&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Services&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;AddSingleton&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;MyMessageProcessor&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;var&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; app&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; builder&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Build&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;app&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;MapGet&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, () &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&gt;&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;Hello World!&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// endpoint for receiving messages:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// GET /message?content=my_message_here&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;app&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;MapGet&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;/message&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;    async&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    (&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        [&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;FromQuery&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; &quot;content&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)] &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;?&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; content&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        [&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;FromServices&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;] &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;ILogger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;MyMessage&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;&gt;&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; logger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        [&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;FromServices&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;] &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;ChannelWriter&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;MyMessage&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;&gt;&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; channelWriter&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    ) =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;        logger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;LogInformation&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Message received: {content}&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;content&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;        await&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; channelWriter&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;WriteAsync&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;new&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;content&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;        return&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; Results&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Ok&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// required to begin processing&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;var&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; msgProcessor&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; app&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Services&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;GetService&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;MyMessageProcessor&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;msgProcessor&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;!&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;StartProcessing&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;app&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// message class&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; sealed&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; record&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; MyMessage&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;string&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;? &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Content&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// processor class&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; sealed&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt; class&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; MyMessageProcessor&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    private&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; readonly&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; ILogger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;MyMessageProcessor&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt; &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;logger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    private&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; readonly&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; ChannelReader&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;MyMessage&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt; &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;channelReader&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    public&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; MyMessageProcessor&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;ILogger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;MyMessageProcessor&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt; &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;logger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;                              ChannelReader&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;MyMessage&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;&gt; &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;channelReader&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C79AC&gt;        this&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;logger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; logger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C79AC&gt;        this&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;channelReader&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; =&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; channelReader&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    public&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; void&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; StartProcessing&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;        // starts background thread&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;        // to process messages&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;        Task&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Factory&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;StartNew&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;async&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; () &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;            await&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; foreach&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; (&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3E79AA&gt;var&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; msg&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; in&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; channelReader&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ReadAllAsync&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;                await&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; ProcessMessageAsync&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;msg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        }, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;TaskCreationOptions&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;LongRunning&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt;    private&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3C7AAD&gt; async&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Task&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; ProcessMessageAsync&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt;MyMessage&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; msg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;        logger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;LogInformation&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Processing message: {content}&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;msg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Content&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;        // operations here&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#4183B9&gt;        await&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; Task&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;Delay&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;3000&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;        logger&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;LogInformation&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;(&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;Message processed: {content}&quot;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;, &lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;msg&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;.&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;Content&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To test, open a browser and go to the URL: &lt;code&gt;http://localhost:{port}/message?content=my_message_here&lt;/code&gt;&lt;/p&gt;&lt;p&gt;&lt;video controls src=https://alexandrehtrb.github.io/assets/videos/posts/2024_06_dotnet_channels_en.mp4&gt;&lt;/video&gt;&lt;/p&gt;&lt;h2 id=criteria-analysis tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/asynchronous-architecture-without-queues/#criteria-analysis class=header-anchor&gt;&lt;span&gt;Criteria analysis&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;To decide if an asynchronous architecture suits your case, consider:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Does the user need an immediate response?&lt;/li&gt;&lt;li&gt;Does an individual message take a long time to process?&lt;/li&gt;&lt;li&gt;Does an individual message use a lot of CPU and RAM to process?&lt;/li&gt;&lt;li&gt;Can the messages be handled in batches (many at once)?&lt;/li&gt;&lt;li&gt;Is the volume of messages expected to be high?&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Many positive answers above indicate that it is adequate.&lt;/p&gt;&lt;p&gt;To choose which implementation to use, ask yourself:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Does the processing need to be started immediately?&lt;/li&gt;&lt;li&gt;Does the order of processing matter?&lt;/li&gt;&lt;li&gt;Is there a priority of messages?&lt;/li&gt;&lt;li&gt;Can there be more than one consumer at the same time?&lt;/li&gt;&lt;li&gt;Would the eventual loss of a message be tolerable?&lt;/li&gt;&lt;li&gt;If a message is lost, how to recover it?&lt;/li&gt;&lt;li&gt;If a message is invalid or unprocessable, how to treat it?&lt;/li&gt;&lt;li&gt;If a message was partially processed, would a retry cause troubles?&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The questions above can help you to decide which asynchronous strategy is the best for your scenario.&lt;/p&gt;&lt;h2 id=sources-and-interesting-reads tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/asynchronous-architecture-without-queues/#sources-and-interesting-reads class=header-anchor&gt;&lt;span&gt;Sources and interesting reads&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://g1.globo.com/pop-arte/noticia/2011/04/no-rio-fas-fazem-fila-para-comprar-ingressos-de-show-de-mccartney.html&gt;No Rio, fãs fazem fila para comprar ingressos do show de McCartney (11/04/2011)&lt;/a&gt; (initial image)&lt;/li&gt;&lt;li&gt;&lt;a href=https://www.sqlteam.com/articles/application-locks-or-mutexes-in-sql-server-2005&gt;Application Locks (or Mutexes) in SQL Server 2005&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://aarniala.fi/blog/postgres-advisory-locks/ &gt;Application-level locking with Postgres advisory locks&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://stackoverflow.com/a/20963803&gt;Stack Overflow - Controlling duration of PostgreSQL lock waits&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://www.mongodb.com/community/forums/t/locking-documents-in-mongo/6865&gt;Locking Documents In Mongo&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://redis.io/glossary/redis-queue/ &gt;Redis glossary - Queue&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://redis.io/docs/latest/develop/use/patterns/distributed-locks/ &gt;Redis - Distributed Locks&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://dotnetcoretutorials.com/using-channels-in-net-core-part-1-getting-started/ &gt;Using Channels In C# .NET&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://learn.microsoft.com/en-us/dotnet/core/extensions/channels&gt;.NET docs - Channels&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html&gt;Java docs - ConcurrentLinkedQueue&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Introduction to functional programming</title>
    <link href="https://alexandrehtrb.github.io/posts/2024/06/introduction-to-functional-programming/" />
    <updated>2024-06-05T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2024/06/introduction-to-functional-programming/</id>
    <content type="html">&lt;p&gt;&lt;picture class=my-4&gt;&lt;source alt=&quot;Le Chiffre, 007 Casino Royale&quot; srcset=https://alexandrehtrb.github.io/assets/img/posts/2024_06_cassino_royale_le_chiffre.avif type=image/avif&gt;&lt;img alt=&quot;Le Chiffre, 007 Casino Royale&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_06_cassino_royale_le_chiffre.jpg&gt;&lt;/picture&gt;&lt;/p&gt;&lt;h2 id=paradigms tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/introduction-to-functional-programming/#paradigms class=header-anchor&gt;&lt;span&gt;Paradigms&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;A paradigm is a manner of thinking, observing and describing something; it&#39;s a mental model, through which we understand the things around us. Each person has its own way of seeing the world and this reflects on the things he / she does and makes.&lt;/p&gt;&lt;p&gt;In programming, a code can be written in many different ways with equivalent results — which means that the concept of paradigm also applies.&lt;/p&gt;&lt;p&gt;There are some programming paradigms that are the most popular, among them:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Imperative programming&lt;/strong&gt;: Here, the program is organized around &lt;em&gt;orders&lt;/em&gt;: &quot;do this&quot;, &quot;do that&quot;, &quot;if this, then do this other thing&quot;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Object-oriented programming (OOP)&lt;/strong&gt;: The focus is on &lt;em&gt;who (or what)&lt;/em&gt; performs an action. Each object is an actor responsible for an action, and can call other objects to execute other actions.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Functional programming (FP)&lt;/strong&gt;: In this paradigm, the model revolves around &lt;em&gt;how actions interconnect&lt;/em&gt;. They are joined together like in an assembly line, where the end of a step arrives at the beginning of the next one, and in the end there is a finished product.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=a-little-bit-about-fp tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/introduction-to-functional-programming/#a-little-bit-about-fp class=header-anchor&gt;&lt;span&gt;A little bit about FP&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Functional programming origins are on mathematical functions.&lt;/p&gt;&lt;p&gt;Mathematical functions can be composed, such that the output of one is the input of another:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;f(x) = 3x + 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;g(x) = 2x&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;// compositions&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;f ○ g (x) = f(g(x)) = 3(2x) + 1 = 6x + 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;g ○ f (x) = g(f(x)) = 2(3x + 1) = 6x + 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The same rationale applies for functional programming: the return of a method is frequently used as the input of other method. The concrete example below shows function composition in F#.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;module&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Program &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; f&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; int&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 3&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;x &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;+&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; g&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; int&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;x&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; fg&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; g &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; f &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// f(g(x)), output of g is input of f&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; gf&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; f &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; g &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// g(f(x)), output of f is input of g&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt; [&amp;lt;EntryPoint&gt;]&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; main _ &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        printfn &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;f(1) = &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;%d&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;f&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        printfn &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;g(1) = &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;%d&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;g&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        printfn &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;fg(1) = &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;%d&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;fg&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        printfn &lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;gf(1) = &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;%d&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt;&quot;&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;gf&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;        0&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    // will print:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    // f(1) = 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    // g(1) = 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    // fg(1) = 7&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    // gf(1) = 8&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=when-to-use-functional-programming tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/introduction-to-functional-programming/#when-to-use-functional-programming class=header-anchor&gt;&lt;span&gt;When to use functional programming&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;FP excels in mathematical-related tasks. Think on engineering calculus, accounting, taxes, finances, calendars and statistics. It also handles very well categorizations and pattern detections.&lt;/p&gt;&lt;p&gt;Artificial intelligence and machine learning need heavy mathematics and therefore benefit from functional programming.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Can I call a functional code from a OOP or imperative project?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Yes, you can! Some object-oriented languages allow invoking functional languages, such as C# code interacting with F#, or Java code interacting with Scala.&lt;/p&gt;&lt;h2 id=when-not-to-use-functional-programming tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/introduction-to-functional-programming/#when-not-to-use-functional-programming class=header-anchor&gt;&lt;span&gt;When not to use functional programming&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;For tasks like sending and receiving messages, reading and writing informations in a database, or publishing in a queue, there are not many advantages in favor of FP, because most actions do not interlace to each other. In these cases, a OOP or imperative language is usually better.&lt;/p&gt;&lt;h2 id=f%23-language tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/introduction-to-functional-programming/#f%23-language class=header-anchor&gt;&lt;span&gt;F# language&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;In this article, we will use the F# functional language for a case study. F# uses &lt;a href=https://dotnet.microsoft.com&gt;.NET runtime&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;To setup your machine for F# development, you will need:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://dotnet.microsoft.com/ &gt;.NET SDK&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://visualstudio.microsoft.com/ &gt;Visual Studio&lt;/a&gt; or&lt;/li&gt;&lt;li&gt;&lt;a href=https://code.visualstudio.com/ &gt;VS Code&lt;/a&gt; with &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=faldor20.fsharp-language-server-updated&quot;&gt;F# language server updated extension&lt;/a&gt; (the Ionide extension is no good)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;To create an F# project, enter on the command line:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;mkdir&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; MyFSharpProject&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;cd&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; ./MyFSharpProject/&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;dotnet&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; new&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; console&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; --language&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; F#&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Before we begin, some syntax tips:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Function declaration:&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// note that each parameter has its own pair of parentheses.&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// the last line is what the function returns.&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sum&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; int&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; int&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  x &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;+&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; y&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Anonymous function / lambda:&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;fun&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; x &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;-&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; x &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Discard operator &lt;code&gt;_&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; myTuple&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// only the first part is relevant.&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// the second is discarded `_`&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; _&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; myTuple&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;Pipelining&lt;/em&gt; &lt;code&gt;|&gt;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; numbers&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; [&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 3&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; doble&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; int&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; x &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; increment&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; int&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; x &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;+&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;(*&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;|&gt; means the result of last function is argument &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;for the last parameter of the next function.&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;numbers |&gt; Seq.map(increment)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;is the same as:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;Seq.map(increment)(numbers)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;*)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; doubledIncrementedNumbers&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  numbers &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// 1, 2, 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.map&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;increment&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt; // 2, 3, 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;  |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.map&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;doble&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt; // 4, 6, 8&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=case-study%3A-poker tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/introduction-to-functional-programming/#case-study%3A-poker class=header-anchor&gt;&lt;span&gt;Case study: poker&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;In poker, a player has a hand with five deck cards, each card defined by a suit with a rank. There are four suits (diamonds ♦️, clubs ♣️, hearts ♥️ and spades ♠️) and thirteen ranks (2 to 10, jack J, queen Q, king K, ace A). The cards of a hand can form special combinations and the player that has the rarest combination wins the round.&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Combination&lt;/th&gt;&lt;th&gt;Example&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;th&gt;Chance&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Royal Straight Flush&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;&lt;span style=color:red&gt;A️♦️&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=color:red&gt;K♦️&lt;/span&gt;️&lt;/strong&gt;️, &lt;strong&gt;&lt;span style=color:red&gt;Q♦️&lt;/span&gt;️&lt;/strong&gt;️, &lt;strong&gt;&lt;span style=color:red&gt;J♦️&lt;/span&gt;️&lt;/strong&gt;️, &lt;strong&gt;&lt;span style=color:red&gt;10♦️&lt;/span&gt;️&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Consecutive sequence of a same suit, from 10 to ace.&lt;/td&gt;&lt;td&gt;0,000154%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Straight Flush&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;5♣️&lt;/strong&gt;, &lt;strong&gt;6♣️&lt;/strong&gt;,️ &lt;strong&gt;7♣️&lt;/strong&gt;,️ &lt;strong&gt;8♣️&lt;/strong&gt;, &lt;strong&gt;9♣️&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Consecutive sequence of a same suit (except the royal, above).&lt;/td&gt;&lt;td&gt;0,00139%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Four of a kind&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;J♣️&lt;/strong&gt;, &lt;strong&gt;J♠️&lt;/strong&gt;,️ &lt;strong&gt;&lt;span style=color:red&gt;J♦️&lt;/span&gt;️&lt;/strong&gt;️,️ &lt;strong&gt;&lt;span style=color:red&gt;J♥️&lt;/span&gt;️&lt;/strong&gt;️, 2♣️️&lt;/td&gt;&lt;td&gt;Four cards with the same rank.&lt;/td&gt;&lt;td&gt;0,02401%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Full House&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;4♣️&lt;/strong&gt;, &lt;strong&gt;&lt;span style=color:red&gt;4♦️&lt;/span&gt;️&lt;/strong&gt;️,️ &lt;strong&gt;&lt;span style=color:red&gt;10♦️&lt;/span&gt;️&lt;/strong&gt;, &lt;strong&gt;10♣️️&lt;/strong&gt;, &lt;strong&gt;10♠️&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Three cards of a rank and two of another rank.&lt;/td&gt;&lt;td&gt;0,1441%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Flush&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;&lt;span style=color:red&gt;4♥️&lt;/span&gt;️&lt;/strong&gt;️, &lt;strong&gt;&lt;span style=color:red&gt;7♥️&lt;/span&gt;️&lt;/strong&gt;️,️ &lt;strong&gt;&lt;span style=color:red&gt;8♥️&lt;/span&gt;️&lt;/strong&gt;️, &lt;strong&gt;&lt;span style=color:red&gt;J♥️&lt;/span&gt;️&lt;/strong&gt;️, &lt;strong&gt;&lt;span style=color:red&gt;A♥️&lt;/span&gt;️&lt;/strong&gt;️&lt;/td&gt;&lt;td&gt;All cards with the same suit, but no consecutive sequence.&lt;/td&gt;&lt;td&gt;0,1965%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Straight&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;&lt;span style=color:red&gt;A♥️&lt;/span&gt;️&lt;/strong&gt;️, &lt;strong&gt;2♣️&lt;/strong&gt;,️ &lt;strong&gt;&lt;span style=color:red&gt;3♥️&lt;/span&gt;️&lt;/strong&gt;️, &lt;strong&gt;&lt;span style=color:red&gt;4♦️&lt;/span&gt;️&lt;/strong&gt;️, &lt;strong&gt;5♠️&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Consecutive sequence of ranks, but cards with different suits.&lt;/td&gt;&lt;td&gt;0,3925%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Three of a kind&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;span style=color:red&gt;2♦️&lt;/span&gt;️, K♣️,️ &lt;strong&gt;&lt;span style=color:red&gt;7♦️&lt;/span&gt;️&lt;/strong&gt;️, &lt;strong&gt;7♣️&lt;/strong&gt;, &lt;strong&gt;7♠️&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Three cards with the same rank.&lt;/td&gt;&lt;td&gt;2,1128%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Two pair&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;&lt;span style=color:red&gt;8♥️&lt;/span&gt;️&lt;/strong&gt;️,️ &lt;strong&gt;&lt;span style=color:red&gt;8♦️&lt;/span&gt;️&lt;/strong&gt;️, &lt;strong&gt;&lt;span style=color:red&gt;9♥️&lt;/span&gt;️&lt;/strong&gt;️, &lt;strong&gt;9♠️&lt;/strong&gt;, &lt;span style=color:red&gt;7♥️&lt;/span&gt;️&lt;/td&gt;&lt;td&gt;One pair of a rank and another pair of a different rank.&lt;/td&gt;&lt;td&gt;4,7539%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Pair&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;span style=color:red&gt;10♦️&lt;/span&gt;️,️ &lt;strong&gt;K♠️&lt;/strong&gt;, &lt;strong&gt;&lt;span style=color:red&gt;K♥️&lt;/span&gt;️&lt;/strong&gt;️, 2♠️, 5♠️&lt;/td&gt;&lt;td&gt;Two cards with the same rank.&lt;/td&gt;&lt;td&gt;42,2569%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;High card&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;span style=color:red&gt;6♦️&lt;/span&gt;️, &lt;span style=color:red&gt;3♦️&lt;/span&gt;️, &lt;strong&gt;&lt;span style=color:red&gt;10♥️&lt;/span&gt;️&lt;/strong&gt;,️ &lt;span style=color:red&gt;7♦️&lt;/span&gt;️, &lt;span style=color:red&gt;2♦️&lt;/span&gt;️&lt;/td&gt;&lt;td&gt;When the combination does not match one of the above.&lt;/td&gt;&lt;td&gt;50,1177%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h3&gt;Domain code for a poker game&lt;/h3&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;namespace&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Poker.Domain&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;module&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; PokerGame &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    // this is a discriminated union&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    type&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Suit&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Spades &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;|&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Clubs &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;|&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Hearts &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;|&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Diamonds&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    // this is an enum&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    type&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Rank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Two &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Three &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 3&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Four &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 4&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Five &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 5&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Six &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 6&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seven &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 7&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Eight &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 8&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Nine &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 9&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Ten &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 10&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Jack &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 11&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Queen &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 12&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; King &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 13&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Ace &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 14&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    // this is a tuple&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    type&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Card&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Suit &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;*&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Rank&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    type&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Card list&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    type&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; HandRanking&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; RoyalStraightFlush &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; StraightFlush &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 9&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; FourOfAKind &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 8&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; FullHouse &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 7&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Flush &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 6&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Straight &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; ThreeOfAKind &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; TwoPairs &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; OnePair &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    |&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; HighCard &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; hasStraight&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        hand&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.sortBy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(fun&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;_&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;rank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; rank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.pairwise&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.forall&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(fun&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ((&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;_&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;rank1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;),&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;_&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;rank2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;))&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;            (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;int rank2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;int rank1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ||&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;rank2 &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Rank.Ace &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;&amp;&amp;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; rank1 &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Rank.Five&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; hasFlush&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        let&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;someSuit&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; someRank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.head hand&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        hand&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.map &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(fun&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;suit&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;_&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; suit&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.forall &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;((=)&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;someSuit&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; hasKingAndAce&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; hasKing&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.exists&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(fun&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;_&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;rank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; rank &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Rank.King&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; hasAce&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.exists&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(fun&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;_&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;rank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; rank &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Rank.Ace&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        hasKing &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;&amp;&amp;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; hasAce&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; getSortedQuantitiesPerRank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;        hand&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.countBy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(fun&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;_&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; rank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; rank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.sortBy&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(fun&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;_&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; qtyForRank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; qtyForRank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.map&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(fun&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;_&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; qtyForRank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; qtyForRank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; Seq.toList&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;    let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; getHandRanking&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; Hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;        match&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; getSortedQuantitiesPerRank&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; with&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; [&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 4&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ]&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; HandRanking.FourOfAKind&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; [&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 3&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ]&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; HandRanking.FullHouse&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; [&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 3&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ]&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; HandRanking.ThreeOfAKind&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; [&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ]&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; HandRanking.TwoPairs&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; [&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 1&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;;&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 2&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; ]&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; HandRanking.OnePair&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;        |&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; _&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; match&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;hasStraight&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;),&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; hasFlush&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;),&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; hasKingAndAce&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;hand&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;))&lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt; with&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;               |&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt;true&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; true&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; true&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; HandRanking.RoyalStraightFlush&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;               |&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt;true&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; true&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; false&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; HandRanking.StraightFlush&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;               |&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt;true&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; false&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; _)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; HandRanking.Straight&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;               |&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; (&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt;false&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt; true&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;,&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; _)&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; HandRanking.Flush&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;               |&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; _&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt; -&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; HandRanking.HighCard&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In only one file, we were able to describe the logic of the problem that needs to be resolved. Even if the language syntax is not familiar for those seeing it for the first time, there is a logical consistency of transformations and comparisons in the methods.&lt;/p&gt;&lt;p&gt;The last method, &lt;code&gt;getHandRanking&lt;/code&gt;, compares the quantities of cards by rank to know if there is a combination by quantity (four-of-a-kind, full house, three-of-a-kind, two pairs, pair). If there are none, then analyses if the combination is sequential and/or by suits (straight, flush, straight flush and royal straight flush). In the end, if there are no matches, then it is a high card ranking.&lt;/p&gt;&lt;p&gt;I confess that when I first used a functional language I found it difficult, a bit because of the syntax which is very unique, and because many code examples on the internet use implicit typing, which is less obvious to understand:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// implicit typing (inference)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sum x y &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  x &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;+&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; y&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;// most explicit typing available&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;let&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt; sum&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;x&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; int&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;)(&lt;/span&gt;&lt;span style=color:#001080;--shiki-dark:#65A5C7&gt;y&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;:&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; int&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;):&lt;/span&gt;&lt;span style=color:#267f99;--shiki-dark:#39AC95&gt; int &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;  x &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;+&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; y&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Nevertheless, if you have a situation where a functional approach is better, I say that it&#39;s worth to persist and learn, starting with simpler and smaller examples, and advancing as you feel more confident.&lt;/p&gt;&lt;p&gt;The code above is available on &lt;a href=https://github.com/alexandrehtrb/FunctionalPoker/ &gt;GitHub&lt;/a&gt;, with unit tests and showing how to integrate a F# project with a C# project.&lt;/p&gt;&lt;h4&gt;fs files for compilation&lt;/h4&gt;&lt;p&gt;If you are using VS Code, whenever you add a new &lt;code&gt;.fs&lt;/code&gt; file to your project, remember to include it in your &lt;code&gt;.fsproj&lt;/code&gt;:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;ItemGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;Compile&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; Include&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;Library.fs&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;Compile&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; Include&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;Module2.fs&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;ItemGroup&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=sources-and-interesting-reads tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/06/introduction-to-functional-programming/#sources-and-interesting-reads class=header-anchor&gt;&lt;span&gt;Sources and interesting reads&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://www.007.com/focus-of-the-week-le-chiffre/ &gt;Le Chiffre, 007 villain image&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://en.wikipedia.org/wiki/Paradigm&gt;Wikipédia - Paradigm&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://en.wikipedia.org/wiki/Poker_probability&gt;Wikipédia - Poker probability&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://fsprojects.github.io/fsharp-cheatsheet/ &gt;F# cheatsheet&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://camilotk.github.io/fsharp-by-example/ &gt;F# by example&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=https://fsharpforfunandprofit.com/ &gt;F# for fun and profit&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Pipelines for .NET</title>
    <link href="https://alexandrehtrb.github.io/posts/2024/04/pipelines-for-dotnet/" />
    <updated>2024-04-29T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2024/04/pipelines-for-dotnet/</id>
    <content type="html">&lt;h2 id=pipelines tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/04/pipelines-for-dotnet/#pipelines class=header-anchor&gt;&lt;span&gt;Pipelines&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Pipelines are sequences of commands that are executed to ensure the integrity of the code and to produce a final artifact, such as an executable program or a library.&lt;/p&gt;&lt;p&gt;Having a pipeline means having a consistent process that mitigates the risk of human errors in the final product and saves the programmer&#39;s time, because he/she can take care of other tasks while the code is compiled, verified and packed.&lt;/p&gt;&lt;p&gt;&lt;picture class=my-4&gt;&lt;source alt=&quot;Conveyor belt&quot; srcset=https://alexandrehtrb.github.io/assets/img/posts/2024_04_conveyor_belt.avif type=image/avif&gt;&lt;img alt=&quot;Conveyor belt&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_04_conveyor_belt.jpg&gt;&lt;/picture&gt;&lt;/p&gt;&lt;h2 id=steps tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/04/pipelines-for-dotnet/#steps class=header-anchor&gt;&lt;span&gt;Steps&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;pre&gt;&lt;code class=language-mermaid&gt;&lt;div class=mermaid&gt;flowchart TD
    checkout --&gt;
    clean --&gt; 
    restore --&gt;
    audit --&gt;
    sbom --&gt;
    build --&gt;
    unittests[unit tests]
    unittests --if program--&gt; publish --with docker--&gt; dockerk8s[docker / kubernetes]
    publish --no docker--&gt; zipinstaller[zip / installer]
    unittests --if nuget package--&gt; pack --&gt; nugetpush[nuget push]
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;checkout&lt;/h3&gt;&lt;p&gt;Fetches the code from the Git branch. If it&#39;s an integration (CI) process, the branch is the one that intends to be merged; if it&#39;s a deployment (CD), the code is from the release branch, such as &lt;em&gt;develop&lt;/em&gt;, &lt;em&gt;master&lt;/em&gt; or &lt;em&gt;release_candidate&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Command line: &lt;code&gt;git clone&lt;/code&gt;&lt;/p&gt;&lt;h3&gt;clean&lt;/h3&gt;&lt;p&gt;Cleans the &lt;em&gt;bin&lt;/em&gt; and &lt;em&gt;obj&lt;/em&gt; folders, to guarantee that everything will start from zero, with no interferences from previous compilations.&lt;/p&gt;&lt;p&gt;Command line: &lt;code&gt;dotnet clean&lt;/code&gt;&lt;/p&gt;&lt;h3&gt;restore&lt;/h3&gt;&lt;p&gt;Guarantees that the references between projects in the solution are correct and downloads the required NuGet packages.&lt;/p&gt;&lt;p&gt;Command line: &lt;code&gt;dotnet restore&lt;/code&gt;&lt;/p&gt;&lt;h3&gt;audit&lt;/h3&gt;&lt;p&gt;Verifies if there are any NuGet packages in the project with security problems, checking in the &lt;a href=https://cve.mitre.org/ &gt;CVE&lt;/a&gt; (&lt;em&gt;Common Vulnerabilities and Exposures&lt;/em&gt;) and &lt;a href=https://github.com/advisories&gt;GHSA&lt;/a&gt; (&lt;em&gt;GitHub Advisory Database&lt;/em&gt;) lists.&lt;/p&gt;&lt;p&gt;Command line: &lt;code&gt;dotnet list package --vulnerable --include-transitive&lt;/code&gt;&lt;/p&gt;&lt;h3&gt;sbom&lt;/h3&gt;&lt;p&gt;SBOM, &lt;em&gt;software bill of materials&lt;/em&gt;, is a document that informs which components were used to produce a program or a library.&lt;/p&gt;&lt;p&gt;This document is of utmost importance for critical software, because with it, organizations can easily know which of its applications are in danger when a vulnerability in a library is reported. After the &lt;a href=https://www.eetimes.com/solarwinds-fallout-are-sboms-the-answer/ &gt;2020 cyberattack on the USA government&lt;/a&gt;, SBOMs became endorsed by the White House.&lt;/p&gt;&lt;p&gt;I recommend the &lt;a href=https://github.com/CycloneDX/cyclonedx-dotnet&gt;CycloneDX&lt;/a&gt; format, for being more succinct and easier to read.&lt;/p&gt;&lt;p&gt;Command line:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;In CycloneDX format: &lt;code&gt;dotnet CycloneDX&lt;/code&gt;&lt;/li&gt;&lt;li&gt;In SPDX format: &lt;code&gt;sbom-tool generate&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;build&lt;/h3&gt;&lt;p&gt;Compiles the solution code.&lt;/p&gt;&lt;p&gt;Command line: &lt;code&gt;dotnet build&lt;/code&gt;&lt;/p&gt;&lt;h3&gt;unit tests&lt;/h3&gt;&lt;p&gt;Runs the solution&#39;s unit tests to ensure that they are passing.&lt;/p&gt;&lt;p&gt;In this step, we can produce a report that shows the coverage level of the unit tests against the code, revealing which classes, methods and lines were covered by the tests. &lt;a href=https://reportgenerator.io&gt;ReportGenerator&lt;/a&gt; is the main tool for these reports in .NET projects.&lt;/p&gt;&lt;p&gt;Command line:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Unit tests: &lt;code&gt;dotnet test&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Coverage report: &lt;code&gt;reportgenerator&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;publish&lt;/h3&gt;&lt;p&gt;Generates the final program for execution. This step differs from build because here certain compilation options can be specified, like the target runtime, self-contained, single-file, and others.&lt;/p&gt;&lt;p&gt;Command line: &lt;code&gt;dotnet publish&lt;/code&gt;&lt;/p&gt;&lt;h3&gt;pack&lt;/h3&gt;&lt;p&gt;Makes a NuGet package, in case of a code that is meant to be a library.&lt;/p&gt;&lt;p&gt;Command line: &lt;code&gt;dotnet pack&lt;/code&gt;&lt;/p&gt;&lt;h3&gt;nuget push&lt;/h3&gt;&lt;p&gt;Uploads the package to a NuGet server, private or public, so it can be used by other people.&lt;/p&gt;&lt;p&gt;Command line: &lt;code&gt;dotnet nuget push&lt;/code&gt;&lt;/p&gt;&lt;h2 id=pipeline-engines tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/04/pipelines-for-dotnet/#pipeline-engines class=header-anchor&gt;&lt;span&gt;Pipeline engines&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;There are many pipeline engines available, such as GitHub Actions, GitLab CI, Jenkins, Azure Pipelines, CircleCI and many others.&lt;/p&gt;&lt;p&gt;You can also have your pipeline as a script, to run locally in your machine. This is a good practice for being a safeguard when your remote pipeline is unavailable or offline and because you can test modifications before commiting them.&lt;/p&gt;&lt;p&gt;I personally recommend using &lt;a href=https://github.com/PowerShell/PowerShell&gt;PowerShell&lt;/a&gt; scripts for local pipelines, because it&#39;s a multiplatform and friendly language, with easy interaction with XML and JSON. Nevertheless, you can use other scripting languages, like Batch, Shell, Python and others you like.&lt;/p&gt;&lt;h2 id=github-actions-example-for-.net-program tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/04/pipelines-for-dotnet/#github-actions-example-for-.net-program class=header-anchor&gt;&lt;span&gt;GitHub Actions example for .NET program&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Publish console / API / desktop program&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt;on&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;  workflow_dispatch&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;# manual trigger&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    inputs&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      version&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        required&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        type&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;string&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      rid&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        required&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        default&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;linux-x64&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt; # where the program will run&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        type&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;string&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;        # https://learn.microsoft.com/en-us/dotnet/core/rid-catalog&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;jobs&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;  generate_program&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    runs-on&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    env&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      OUTPUT_FOLDER&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;${{ format(&#39;./out/{0}/&#39;, inputs.rid) }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      VERSION_NAME&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;${{ inputs.version }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      RID&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;${{ inputs.rid }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    steps&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Checkout&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      uses&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;actions/checkout@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      with&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        fetch-depth&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Install .NET SDK&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      uses&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;actions/setup-dotnet@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      with&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        dotnet-version&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;8.x&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt; # .NET version here&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Install CycloneDX .NET&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;dotnet tool install --global CycloneDX&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Clean solution&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;dotnet clean --nologo --verbosity quiet&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Restore solution&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;dotnet restore --nologo --verbosity quiet&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Audit solution&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      shell&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;pwsh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        $projectPath = &quot;./src/MyProject.Console/MyProject.Console.csproj&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        $jsonObj = (dotnet list $projectPath package --vulnerable --include-transitive --format json) | ConvertFrom-Json;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        $hasAnyVulnerability = ($jsonObj.projects[0].frameworks -ne $null);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        if ($hasAnyVulnerability) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;          dotnet list package --vulnerable --include-transitive;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;          exit 1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Build solution&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;dotnet build --no-restore --configuration Release --nologo --verbosity quiet&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Run unit tests&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;dotnet test --no-build --configuration Release --nologo --verbosity quiet --collect:&quot;XPlat Code Coverage&quot; --results-directory ./TestResults/&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Unit tests coverage report&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      uses&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;danielpalme/ReportGenerator-GitHub-Action@5.2.4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      with&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        reports&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;TestResults/**/coverage.cobertura.xml&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        targetdir&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;TestResults&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        reporttypes&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;JsonSummary;Html&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Generate SBOM&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      shell&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;pwsh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;dotnet CycloneDX ./src/MyProject.Console/MyProject.Console.csproj -o $env:OUTPUT_FOLDER -f sbom.json -sv $env:VERSION_NAME --json&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Publish program&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      shell&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;pwsh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        dotnet publish ./src/MyProject.Console/MyProject.Console.csproj `&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        --verbosity quiet `&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        --nologo `&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        --configuration Release `&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        -p:PublishSingleFile=true `&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        -p:Version=${env:VERSION_NAME} `&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        --self-contained true `&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        --runtime ${env:RID} `&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        --output ${env:OUTPUT_FOLDER};&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Set execution attributes (UNIX only)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      if&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;${{ startsWith(inputs.rid, &#39;linux&#39;) || startsWith(inputs.rid, &#39;osx&#39;) }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      shell&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;pwsh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;chmod +x &quot;${env:OUTPUT_FOLDER}/MyProject.Console&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Pack program&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      shell&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;pwsh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        $zipName = &quot;MyProject.Console_${env:VERSION_NAME}_${env:RID}.zip&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        # if Linux or MacOSX, we should use zip instead of Compress-Archive,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        # to preserve the Unix file attributes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        if ($IsWindows) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;          Compress-Archive -CompressionLevel Optimal -Path $env:OUTPUT_FOLDER -DestinationPath &quot;./out/${zipName}&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        } else {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;          cd $env:OUTPUT_FOLDER&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;          zip -9 -r ../${zipName} *&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;          cd ../..&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        Remove-Item $env:OUTPUT_FOLDER -Force -Recurse -ErrorAction Ignore&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        echo &quot;OUTPUT_FILE_NAME=${zipName}&quot; | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Upload program to workflow results&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      uses&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;actions/upload-artifact@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      with&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        compression-level&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;0&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt; # previous step already compresses&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;${{ env.OUTPUT_FILE_NAME }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        path&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;${{ format(&#39;./out/{0}&#39;, env.OUTPUT_FILE_NAME) }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Upload SBOM to workflow results&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      uses&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;actions/upload-artifact@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      with&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;sbom.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        path&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;./out/sbom.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Upload coverage report to workflow results&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      uses&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;actions/upload-artifact@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      with&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;coverage_report&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        path&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;TestResults&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    # other subsequent steps can be added here,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    # like docker and kubernetes,&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;    # or installer generation, in case of desktop programs.&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=github-actions-example-for-nuget-package tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/04/pipelines-for-dotnet/#github-actions-example-for-nuget-package class=header-anchor&gt;&lt;span&gt;GitHub Actions example for NuGet package&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Publish NuGet package&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#3A6A91&gt;on&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;  workflow_dispatch&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;# manual trigger&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;jobs&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;  generate_nuget_package&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    runs-on&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;    steps&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Checkout&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      uses&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;actions/checkout@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      with&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        fetch-depth&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Install .NET SDK&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      uses&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;actions/setup-dotnet@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      with&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        dotnet-version&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;8.x&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt; # .NET version here&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Install CycloneDX .NET&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;dotnet tool install --global CycloneDX&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Clean solution&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;dotnet clean --nologo --verbosity quiet&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Restore solution&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;dotnet restore --nologo --verbosity quiet&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Audit solution&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      shell&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;pwsh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        $projectPath = &quot;./src/MyProject.Console/MyProject.Console.csproj&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        $jsonObj = (dotnet list $projectPath package --vulnerable --include-transitive --format json) | ConvertFrom-Json;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        $hasAnyVulnerability = ($jsonObj.projects[0].frameworks -ne $null);&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        if ($hasAnyVulnerability) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;          dotnet list package --vulnerable --include-transitive;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;          exit 1;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Build solution&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;dotnet build --no-restore --configuration Release --nologo --verbosity quiet&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Run unit tests&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;dotnet test --no-build --configuration Release --nologo --verbosity quiet --collect:&quot;XPlat Code Coverage&quot; --results-directory ./TestResults/&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Unit tests coverage report&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      uses&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;danielpalme/ReportGenerator-GitHub-Action@5.2.4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      with&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        reports&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;TestResults/**/coverage.cobertura.xml&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        targetdir&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;TestResults&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        reporttypes&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;JsonSummary;Html&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Read package version&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      shell&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;pwsh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        # PackageVersion needs to be declared in .csproj&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        ([XML]$nugetCsprojXml = Get-Content ./src/MyProject.Library/MyProject.Library.csproj)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        $versionName = $nugetCsprojXml.Project.PropertyGroup.PackageVersion&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        # adds to workflow environment variables&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        echo &quot;VERSION_NAME=${versionName}&quot; | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Generate SBOM&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      shell&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;pwsh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;dotnet CycloneDX ./src/MyProject.Library/MyProject.Library.csproj -o ./out/ -f sbom_MyProject_Library.json -sv $env:VERSION_NAME --json&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Generate package&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;dotnet pack ./src/MyProject.Library/MyProject.Library.csproj --nologo --verbosity quiet --configuration Release&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Upload package to NuGet server&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      shell&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;pwsh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      run&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#af00db;--shiki-dark:#9C5E97&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        $filePath = &quot;./src/MyProject.Library/bin/Release/MyProject.Library.${env:VERSION_NAME}.nupkg&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        dotnet nuget push $filePath --api-key $env:NUGET_API_KEY --source https://api.nuget.org/v3/index.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        # if it&#39;s a private NuGet, specify other source.&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        # web portal for testing NuGet uploads: https://int.nugettest.org&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;        # source for testing: https://apiint.nugettest.org/v3/index.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      env&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        NUGET_API_KEY&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;${{ secrets.MY_NUGET_API_KEY }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Upload package to workflow results&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      uses&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;actions/upload-artifact@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      with&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        compression-level&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt;0&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt; # .nupkg already is a compressed zip&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;${{ format(&#39;MyProject.Library.{0}.nupkg&#39;, env.VERSION_NAME) }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        path&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;${{ format(&#39;./src/MyProject.Library/bin/Release/MyProject.Library.{0}.nupkg&#39;, env.VERSION_NAME) }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Upload SBOM to workflow results&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      uses&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;actions/upload-artifact@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      with&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;sbom_MyProject_Library.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        path&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;./out/sbom_MyProject_Library.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;    - &lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;Upload coverage report to workflow results&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      uses&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;actions/upload-artifact@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;      with&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        name&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;coverage_report&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;        path&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;: &lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;TestResults&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=image-source tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/04/pipelines-for-dotnet/#image-source class=header-anchor&gt;&lt;span&gt;Image source&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;a href=https://dyno.co.nz/products/telescopic-and-expandable-conveyors/telescopic-conveyor/ &gt;https://dyno.co.nz/products/telescopic-and-expandable-conveyors/telescopic-conveyor/&lt;/a&gt;&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>HTTP/2 and HTTP/3 explained
</title>
    <link href="https://alexandrehtrb.github.io/posts/2024/03/http2-and-http3-explained/" />
    <updated>2024-03-11T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2024/03/http2-and-http3-explained/</id>
    <content type="html">&lt;p&gt;In the beginning of the 1990s, Tim Berners-Lee and his team at &lt;a href=https://home.cern&gt;CERN&lt;/a&gt; worked together to elaborate the basis of the World Wide Web, defining four building blocks for the Internet:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;A document format for hypertext (HTML)&lt;/li&gt;&lt;li&gt;A data transmission protocol (HTTP)&lt;/li&gt;&lt;li&gt;A web browser to view hypertext (the first browser, WorldWideWeb)&lt;/li&gt;&lt;li&gt;A server to transmit the data (an early version of httpd)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;HTTP reused for data transport the existing TCP/IP protocols, with HTTP message bytes residing in the &lt;a href=https://en.wikipedia.org/wiki/Application_layer&gt;application layer&lt;/a&gt;, light blue in the image below.&lt;/p&gt;&lt;img alt=&quot;OSI model&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2024_03_osi_model_tcp_ip.png&gt;&lt;h2 id=http%2F0.9 tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/03/http2-and-http3-explained/#http%2F0.9 class=header-anchor&gt;&lt;span&gt;HTTP/0.9&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;It was the first HTTP draft. The only existing method was &lt;code&gt;GET&lt;/code&gt;; there were no headers nor status codes; and the only data format available was HTML. Just like in HTTP/1.0 and HTTP/1.1, the HTTP messages were in an ASCII text structure.&lt;/p&gt;&lt;p&gt;Example of a HTTP/0.9 request:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;GET /mypage.html&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Response example:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;&amp;lt;html&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;  A very simple HTML page&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&amp;lt;/html&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=http%2F1.0 tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/03/http2-and-http3-explained/#http%2F1.0 class=header-anchor&gt;&lt;span&gt;HTTP/1.0&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;This version gave to HTTP its current structure, similar to a &lt;a href=https://www.learninghub.ac.nz/writing/writing/writing-a-memorandum/ &gt;memorandum&lt;/a&gt;, also introducing new methods (&lt;code&gt;HEAD&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt;), MIME types, status codes and protocol versioning.&lt;/p&gt;&lt;p&gt;Example of a HTTP/1.0 request:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;GET /mypage.html HTTP/1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Response example:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;200 OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Date: Tue, 15 Nov 1994 08:12:31 GMT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Server: CERN/3.0 libwww/2.17&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Content-Type: text/html&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&amp;lt;HTML&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;A page with an image&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;  &amp;lt;IMG SRC=&quot;/myimage.gif&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&amp;lt;/HTML&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=http%2F1.1 tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/03/http2-and-http3-explained/#http%2F1.1 class=header-anchor&gt;&lt;span&gt;HTTP/1.1&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;This version came up in early 1997, few months after its predecessor. The main changes were:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Persistent TCP connections (keep-alive), saving machine and network resources. In the previous version, a new TCP connection was opened for each request and closed after the response.&lt;/li&gt;&lt;li&gt;&lt;code&gt;Host&lt;/code&gt; header, allowing more than one server under the same IP.&lt;/li&gt;&lt;li&gt;Header conventions for encoding, cache, language and MIME type.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Example of a HTTP/1.1 request:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;GET /api/fruit/orange HTTP/1.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Host: www.fruityvice.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Accept-Encoding: gzip, deflate, br&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Response example:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Server: nginx/1.16.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Date: Sun, 10 Mar 2024 20:44:25 GMT&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Transfer-Encoding: chunked&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Connection: keep-alive&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;X-Content-Type-Options: nosniff&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;X-XSS-Protection: 1; mode=block&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Cache-Control: no-store, must-revalidate, no-cache, max-age=0&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Pragma: no-cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;X-Frame-Options: DENY&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Content-Type: application/json&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;Expires: 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;{&quot;name&quot;:&quot;Orange&quot;,&quot;id&quot;:2,&quot;family&quot;:&quot;Rutaceae&quot;,&quot;order&quot;:&quot;Sapindales&quot;,&quot;genus&quot;:&quot;Citrus&quot;,&quot;nutritions&quot;:{&quot;calories&quot;:43,&quot;fat&quot;:0.2,&quot;sugar&quot;:8.2,&quot;carbohydrates&quot;:8.3,&quot;protein&quot;:1.0}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;img alt=&quot;HTTP1 in TCP packets&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2024_03_http1_tcp_packets.png&gt;&lt;h2 id=http%2F2 tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/03/http2-and-http3-explained/#http%2F2 class=header-anchor&gt;&lt;span&gt;HTTP/2&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;In 2015, after many years of observation and studies on the performance of the Internet, the HTTP/2 was proposed and created, based on Google&#39;s SPDY.&lt;/p&gt;&lt;p&gt;Among its differences, were the multiplexing of many messages in a single TCP packet; binary format of the messages; and HPACK compression for headers.&lt;/p&gt;&lt;p&gt;In HTTP/1.1, two requests cannot ride together the same TCP connection — it is necessary that the first one ends for the subsequent to begin. This is called &lt;em&gt;head-of-line blocking&lt;/em&gt;. In the diagram below, request 2 cannot be sent until response 1 arrives, considering that only one TCP connection is used.&lt;/p&gt;&lt;pre&gt;&lt;code class=language-mermaid&gt;&lt;div class=mermaid&gt;sequenceDiagram
    Client-&gt;&gt;+Server: req 1
    Server--&gt;&gt;-Client: res 1
    Client-&gt;&gt;+Server: req 2
    Server--&gt;&gt;-Client: res 2
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With HTTP/2, this problem is solved with &lt;em&gt;streams&lt;/em&gt;, each stream corresponds to a message. Many streams can be interleaved in a single TCP packet. If a stream can&#39;t emit its data for some reason, other streams can take its place in the TCP packet.&lt;/p&gt;&lt;p&gt;HTTP/2 streams are divided in &lt;em&gt;frames&lt;/em&gt;, each one containing: the frame type, the stream that it belongs to, and the length in bytes. In the diagram below, a coloured rectangle is a TCP packet and a ✉ is a HTTP/2 frame inside it. The first and third TCP packets carry frames of different streams.&lt;/p&gt;&lt;pre&gt;&lt;code class=language-mermaid&gt;&lt;div class=mermaid&gt;sequenceDiagram
    rect rgb(239, 190, 125)
        Client-&gt;&gt;+Server: req1: #9993;1/1&amp;lt;br&gt;+&amp;lt;br&gt;req2: #9993;1/1
    end
    rect rgb(197, 234, 189)
        Server--&gt;&gt;Client: res1: #9993;1/2
    end
    rect rgb(197, 234, 189)
        Server--&gt;&gt;-Client: res1: #9993;2/2&amp;lt;br&gt;+&amp;lt;br&gt;res2: #9993;1/1
    end
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The image below shows how frames go inside a TCP packet. Stream 1 carries a HTTP response for a JavaScript file and stream 2 carries a HTTP response for a CSS file.&lt;/p&gt;&lt;img alt=&quot;HTTP2 frames in TCP packets&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2024_03_http2_tcp_packets.png&gt;&lt;h2 id=http%2F3 tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/03/http2-and-http3-explained/#http%2F3 class=header-anchor&gt;&lt;span&gt;HTTP/3&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;HTTP/3 was born from a new transport protocol, QUIC, created by Google in 2012. QUIC is encapsulated inside UDP, and compared to TCP, it proposes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;fewer packet roundtrips to establish connection and TLS authentication;&lt;/li&gt;&lt;li&gt;more resilient connections regarding packet losses;&lt;/li&gt;&lt;li&gt;to solve the head-of-line blocking that exists in TCP and TLS.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;HTTP/2 solves the HTTP head-of-line blocking, but, this problem also happens with TCP and TLS. TCP understands that the data it needs to send is a contiguous sequence of packets, and if any packet is lost, it must be resent, in order to preserve information integrity. &lt;em&gt;With TCP, subsequent packets cannot be sent until the lost packet successfully arrives to the destination.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;The diagram below explains visually how this happens in HTTP/2. The second packet only had frames of response 1, but its loss delays both response 1 and response 2 — that means that in this case, there is no parallelism.&lt;/p&gt;&lt;pre&gt;&lt;code class=language-mermaid&gt;&lt;div class=mermaid&gt;sequenceDiagram
    rect rgb(239, 190, 125)
        Client-&gt;&gt;+Server: req1: #9993;1/1&amp;lt;br&gt;+&amp;lt;br&gt;req2: #9993;1/1
    end
    rect rgb(197, 234, 189)
        Server--xClient: res1: #9993;1/2
    end
    Note over Client,Server: lost TCP packet&amp;lt;br&gt;must be resent.&amp;lt;br&gt;delays both res1 and res2
    rect rgb(197, 234, 189)
        Server--&gt;&gt;Client: res1: #9993;1/2
    end
    rect rgb(197, 234, 189)
        Server--&gt;&gt;-Client: res1: #9993;2/2&amp;lt;br&gt;+&amp;lt;br&gt;res2: #9993;1/1
    end
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To solve TCP&#39;s head-of-line blocking, QUIC decided to use UDP for its transport protocol, because UDP does not care for guarantees of arrival. The responsibility of data integrity, that in TCP is part of the transport layer, is moved in QUIC to the application layer, and the frames of a message can arrive out of order, without blocking unrelated streams.&lt;/p&gt;&lt;pre&gt;&lt;code class=language-mermaid&gt;&lt;div class=mermaid&gt;sequenceDiagram
    rect rgb(255, 179, 217)
        Client-&gt;&gt;Server: req1: #9993;1/1&amp;lt;br&gt;+&amp;lt;br&gt;req2: #9993;1/1
    end
    rect rgb(179, 205, 230)
        Server--xClient: res1: #9993;1/2
    end
    Note over Client,Server: lost QUIC packet&amp;lt;br&gt;doesn&#39;t block sending&amp;lt;br&gt;other packets
    rect rgb(179, 205, 230)
        Server--&gt;&gt;Client: res1: #9993;2/2&amp;lt;br&gt;+&amp;lt;br&gt;res2: #9993;1/1
    end
    Note over Client,Server: resending lost packet.&amp;lt;br&gt;res2 wasn&#39;t delayed
    rect rgb(179, 205, 230)
        Server--&gt;&gt;Client: res1: #9993;1/2
    end
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;img alt=&quot;HTTP3 QUIC packets&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2024_03_http3_quic_packets.png&gt;&lt;p&gt;The head-of-line blocking related to TLS (SSL) happens on TCP because the cryptography is usually applied over the entire message content, meaning that all data (all packets) needs to be received for the decryption to happen. With QUIC, the cryptography is individual for each QUIC packet, that is decrypted on arrival, without having to receive all packets beforehand.&lt;/p&gt;&lt;p&gt;TLS with TCP:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Input data: &lt;code&gt;A+B+C&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Encrypted data: &lt;code&gt;crypt(A+B+C) = D+E+F&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Packets: &lt;code&gt;D, E, F&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Received: &lt;code&gt;decrypt(D+E+F)&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;A+B+C&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;TLS with QUIC:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Input data: &lt;code&gt;A+B+C&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Encrypted data: &lt;code&gt;crypt(A) = X, crypt(B) = Y, crypt(C) = Z&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Packets: &lt;code&gt;X, Y, Z&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Received: &lt;code&gt;decrypt(X) + decrypt(Y) + decrypt(Z)&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;A+B+C&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h2 id=comparison-table tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/03/http2-and-http3-explained/#comparison-table class=header-anchor&gt;&lt;span&gt;Comparison table&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th style=text-align:center&gt;HTTP/1.1&lt;/th&gt;&lt;th style=text-align:center&gt;HTTP/2&lt;/th&gt;&lt;th style=text-align:center&gt;HTTP/3&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Transport&lt;/strong&gt;&lt;br&gt;&lt;strong&gt;protocol&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;TCP,&lt;br&gt;persistent connection&lt;/td&gt;&lt;td style=text-align:center&gt;TCP,&lt;br&gt;persistent connection&lt;/td&gt;&lt;td style=text-align:center&gt;UDP,&lt;br&gt;persistent connection&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Head-of-line&lt;/strong&gt;&lt;br&gt;&lt;strong&gt;blocking&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;HTTP/1.x HOL&lt;br&gt;TCP HOL&lt;br&gt;TLS HOL&lt;/td&gt;&lt;td style=text-align:center&gt;TCP HOL&lt;br&gt;TLS HOL&lt;/td&gt;&lt;td style=text-align:center&gt;-&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Message format&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;ASCII text&lt;/td&gt;&lt;td style=text-align:center&gt;binary&lt;/td&gt;&lt;td style=text-align:center&gt;binary&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Header compression&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;-&lt;/td&gt;&lt;td style=text-align:center&gt;HPACK&lt;/td&gt;&lt;td style=text-align:center&gt;QPACK&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Number of roundtrips&lt;/strong&gt;&lt;br&gt;&lt;strong&gt;before start&lt;/strong&gt;&lt;br&gt;&lt;strong&gt;(handshakes)&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;br&gt;1 from TCP&lt;br&gt;+2 from TLS 1.2*&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;br&gt;1 from TCP&lt;br&gt;+1 from TLS 1.3*&lt;/td&gt;&lt;td style=text-align:center&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;br&gt;0 from UDP&lt;br&gt;+0 from TLS 1.3 with 0-RTT*&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Connection identification&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;source IP and port&lt;/td&gt;&lt;td style=text-align:center&gt;source IP and port&lt;/td&gt;&lt;td style=text-align:center&gt;connection ID**,&lt;br&gt;resistant to IP changes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Cryptography&lt;/strong&gt;&lt;/td&gt;&lt;td style=text-align:center&gt;optional;&lt;br&gt;applied over the entire message&lt;/td&gt;&lt;td style=text-align:center&gt;optional;&lt;br&gt;applied over the entire message&lt;/td&gt;&lt;td style=text-align:center&gt;embedded TLS 1.3;&lt;br&gt;applied over each QUIC packet&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;* TLS 1.2 requires 2 roundtrips for cryptographic handshake and TLS 1.3 requires only 1, with the option for 0-RTT (&lt;em&gt;zero roundtrip time resumption&lt;/em&gt;), where there is no need of previous handshake. &lt;strong&gt;However, 0-RTT enables &lt;a href=https://blog.cloudflare.com/introducing-0-rtt&gt;replay attacks&lt;/a&gt; and therefore is unsafe. This is an optional feature, that can be disabled.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;** QUIC&#39;s connection ID can be used for fingerprinting, posing a risk to user privacy, according to a &lt;a href=https://alexandrehtrb.github.io/assets/misc/2024_03_research_A_QUIC_Look_at_Web_Tracking.pdf&gt;research&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=which-is-the-best-version%3F tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/03/http2-and-http3-explained/#which-is-the-best-version%3F class=header-anchor&gt;&lt;span&gt;Which is the best version?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The two best versions currently are HTTP/2 and HTTP/3.&lt;/p&gt;&lt;p&gt;HTTP/3 was designed for unstable connections, such as cellphone and satellite networks. To counter network instabilities, QUIC has a great degree of independence between the data streams and good resilience if packets are lost. Nevertheless, HTTP/3 has performance penalties, mainly for 1) the UDP protocol wasn&#39;t optimized by routers and operating systems over the last decades due to its low usage, making it comparatively slower than TCP; and 2) the packet-by-packet cryptography used by QUIC requires a greater number of mathematical operations, becoming less efficient than the entire message cryptography used in TCP. Also, there is the issue that the UDP protocol is restricted in some networks to protect against attacks like &lt;a href=https://www.cloudflare.com/learning/ddos/udp-flood-ddos-attack/ &gt;UDP flood attack&lt;/a&gt; and &lt;a href=https://blog.cloudflare.com/deep-inside-a-dns-amplification-ddos-attack&gt;DNS amplification attack&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;On reliable and stable connections, HTTP/2 many times offers better performance than HTTP/3.&lt;/p&gt;&lt;p&gt;To avoid HOL blocking with HTTP/1.x, many web browsers and HTTP clients open multiple TCP connections, so the requests go in parallel. In scenarios with many heavy parallel requests and responses, this technique &lt;em&gt;may&lt;/em&gt; make HTTP/1.x offer a better throughput than HTTP/2 or HTTP/3, however, it is a less efficient way to solve the problem. An alternative solution is having multiple HTTP/2-3 connections at the same time (&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.net.http.socketshttphandler.enablemultiplehttp2connections?view=net-8.0#system-net-http-socketshttphandler-enablemultiplehttp2connections&quot;&gt;C# example&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;Generally speaking, it&#39;s recommended to run compatibility and performance tests to determine which version is the most appropriate, and furthermore, a server can accept both HTTP/2 and HTTP/3 connections, leaving to the client the decision of which version to use.&lt;/p&gt;&lt;h2 id=testing-tools tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/03/http2-and-http3-explained/#testing-tools class=header-anchor&gt;&lt;span&gt;Testing tools&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;I recommend &lt;a href=https://pororoca.io&gt;Pororoca&lt;/a&gt; (made by myself 🙂).&lt;/p&gt;&lt;h2 id=bibliography tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/03/http2-and-http3-explained/#bibliography class=header-anchor&gt;&lt;span&gt;Bibliography&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Evolution_of_HTTP&gt;MDN - Evolution of HTTP&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://developer.mozilla.org/en-US/docs/Web/HTTP/Connection_management_in_HTTP_1.x&gt;MDN - Connection management in HTTP/1.x&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://davidwills.us/cmit265/osi.html&gt;David Wills - OSI reference model&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://calendar.perfplanet.com/2020/head-of-line-blocking-in-quic-and-http-3-the-details/ &gt;Web Performance Calendar - Head-of-Line Blocking in QUIC and HTTP/3: The Details&lt;/a&gt; (&lt;a href=https://web.archive.org/web/20240311184108/https://calendar.perfplanet.com/2020/head-of-line-blocking-in-quic-and-http-3-the-details/ &gt;WebArchive&lt;/a&gt;) &lt;strong&gt;(recommended reading)&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://en.wikipedia.org/wiki/QUIC&gt;Wikipedia - QUIC&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://blog.cloudflare.com/introducing-0-rtt&gt;Cloudflare - Introducing Zero Round Trip Time Resumption (0-RTT)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://http3-explained.haxx.se/en/quic/quic-connections&gt;HTTP/3 explained - QUIC connections&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://svs.informatik.uni-hamburg.de/publications/2019/2019-02-26-Sy-PET_Symposium-A_QUIC_Look_at_Web_Tracking.pdf&gt;Erik Sy*, Christian Burkert, Hannes Federrath, and Mathias Fischer - A QUIC Look at Web Tracking&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;script&gt;function afterMermaidRenderCallback(){isDarkMode()&amp;&amp;document.querySelectorAll(&quot;rect.rect&quot;).forEach(t=&gt;{var r=t.getAttribute(&quot;fill&quot;);&quot;rgb(239, 190, 125)&quot;==r?t.setAttribute(&quot;fill&quot;,&quot;rgb(93, 60, 24)&quot;):&quot;rgb(197, 234, 189)&quot;==r?t.setAttribute(&quot;fill&quot;,&quot;rgb(6, 58, 33)&quot;):&quot;rgb(255, 179, 217)&quot;==r?t.setAttribute(&quot;fill&quot;,&quot;rgb(53, 1, 44)&quot;):&quot;rgb(179, 205, 230)&quot;==r&amp;&amp;t.setAttribute(&quot;fill&quot;,&quot;rgb(0, 30, 69)&quot;)})}&lt;/script&gt;</content>
  </entry>
  <entry>
    <title>Modern image formats: JXL and AVIF
</title>
    <link href="https://alexandrehtrb.github.io/posts/2024/01/modern-image-formats-jxl-and-avif/" />
    <updated>2024-01-28T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2024/01/modern-image-formats-jxl-and-avif/</id>
    <content type="html">&lt;h2 id=computers%2C-photography-and-images tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/modern-image-formats-jxl-and-avif/#computers%2C-photography-and-images class=header-anchor&gt;&lt;span&gt;Computers, photography and images&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The visualization of images is fundamental in many areas, such as arts, professional photography, cartography, astrophotography, diagnostic medicine, historic preservation and movies. The quality of the images is very important to highlight details, like an artistic touch, an imprecision, or an element that is imperceptible at first sight.&lt;/p&gt;&lt;p&gt;On a computer screen, an image is represented by thousands of &lt;em&gt;pixels&lt;/em&gt; (&lt;strong&gt;pic&lt;/strong&gt;ture &lt;strong&gt;el&lt;/strong&gt;ement), each &lt;em&gt;pixel&lt;/em&gt; corresponding to a colour and its intensity. Consider an image of 1,024px x 768px = 768,432 &lt;em&gt;pixels&lt;/em&gt;; if each pixel is RGBA and has 4 &lt;em&gt;bytes&lt;/em&gt;, 1 for red, 1 for green, 1 for blue and 1 for transparency, this image will have a size of 3.1MB, which is quite large. However, by choosing proper compression techniques and file formats, we can have this image with the same quality and with a much lower file size.&lt;/p&gt;&lt;img alt=&quot;Examples of high-resolution images&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_01_hires_images_examples.jpg class=my-4&gt;&lt;h2 id=newer-formats tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/modern-image-formats-jxl-and-avif/#newer-formats class=header-anchor&gt;&lt;span&gt;Newer formats&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Around 2019, two new file formats, JXL and AVIF, came to market promising lower disk usage and better preservation of details.&lt;/p&gt;&lt;p&gt;Both share as characteristics:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Support for lossless and lossy compression at more efficient rates than previous formats, like JPEG and PNG, and with better quality retention.&lt;/li&gt;&lt;li&gt;Support for animations and transparencies.&lt;/li&gt;&lt;li&gt;Open-source and royalty-free licenses.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;JXL&lt;/h3&gt;&lt;p&gt;JXL, or JPEG-XL, began in 2017 with a call for papers for a next-generation image format. The final proposal was the junction of two others: PIK, from Google, and FLIF, from Cloudinary.&lt;/p&gt;&lt;h3&gt;AVIF&lt;/h3&gt;&lt;p&gt;AVIF is a format created by the Alliance for Open Media, an industry-consortium of companies like Netflix, Meta and Google, with the objective of forming standards for multimedia delivery. AVIF&#39;s first specification is from 2018.&lt;/p&gt;&lt;h2 id=when-should-i-use-jxl%3F tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/modern-image-formats-jxl-and-avif/#when-should-i-use-jxl%3F class=header-anchor&gt;&lt;span&gt;When should I use JXL?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;JXL is better for:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Images with high and extremely high resolution and level of details.&lt;/li&gt;&lt;li&gt;When processing speed is important. JXL encoding is 5 to 10 times faster than AVIF&#39;s.&lt;/li&gt;&lt;li&gt;Very high colour precision.&lt;/li&gt;&lt;li&gt;Progressive decoding: the image can be rendered as it is downloaded.&lt;/li&gt;&lt;li&gt;Images with very high dimensions, because it supports sizes of over 1 billion x 1 billion pixels. AVIF supports images at most of 8K resolution (8193px x 4320px).&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=when-should-i-use-avif%3F tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/modern-image-formats-jxl-and-avif/#when-should-i-use-avif%3F class=header-anchor&gt;&lt;span&gt;When should I use AVIF?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;AVIF is better for:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Images in Web pages, because most of the browsers support AVIF (94%), while only few browsers support JXL (15%). Data obtained from &lt;a href=https://caniuse.com/avif&gt;caniuse&lt;/a&gt; (05/08/2025).&lt;/li&gt;&lt;li&gt;Videos and animations, because it has excellent compression rates for them, over 90% in some cases. It&#39;s a great substitute for GIFs.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=compression-and-performance-tests tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/modern-image-formats-jxl-and-avif/#compression-and-performance-tests class=header-anchor&gt;&lt;span&gt;Compression and performance tests&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Examples:&lt;/p&gt;&lt;p&gt;The original image below is a JPEG of 8192x5464, file size 11MB. In JXL format (q=90), the size is 7.3MB. In AVIF (q=90), is 8.3MB.&lt;/p&gt;&lt;img alt=&quot;Escalators in a subway station&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_01_subway_escalators.jpg class=my-4&gt;&lt;p&gt;The original GIF below has a file size of 3.1MB. In JXL format (q=90), the size is 2.5MB. In AVIF (q=90), is 79kB. Impressive!&lt;/p&gt;&lt;p&gt;&lt;picture class=my-4&gt;&lt;source alt=&quot;Emilia Clarke&quot; srcset=https://alexandrehtrb.github.io/assets/img/posts/2024_01_emilia_clarke.avif type=image/avif&gt;&lt;img alt=&quot;Emilia Clarke&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_01_emilia_clarke.gif&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;This &lt;a href=https://github.com/alexandrehtrb/jxl-avif-simple-benchmark&gt;GitHub repo&lt;/a&gt; executes tests to compare compression rates and speeds of JXL and AVIF. The comparison is not qualitative, nor scientific. The input images include:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Animated GIFs of high, medium and low complexity.&lt;/li&gt;&lt;li&gt;JPEG photographies of medium, high and very high resolution.&lt;/li&gt;&lt;li&gt;PNG and JPEG infographics, to evaluate compression of images with texts on them.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=tools tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/modern-image-formats-jxl-and-avif/#tools class=header-anchor&gt;&lt;span&gt;Tools&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;There are websites on the Internet that can convert to AVIF and JXL. I personally recommend &lt;a href=https://ezgif.com&gt;ezgif&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Most browsers support opening &lt;code&gt;.avif&lt;/code&gt; files.&lt;/p&gt;&lt;p&gt;To view JXL, there is &lt;a href=https://www.gimp.org/ &gt;GIMP&lt;/a&gt;, &lt;a href=https://www.irfanview.com/ &gt;Irfanview&lt;/a&gt; and &lt;a href=https://github.com/libjxl/libjxl/blob/main/doc/software_support.md&gt;other programs&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;Conversion to &lt;code&gt;.jxl&lt;/code&gt;&lt;/h3&gt;&lt;p&gt;To convert an image to JXL, using the &lt;a href=https://github.com/libjxl/libjxl&gt;official tool&lt;/a&gt;:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;cjxl&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; input_image.jpg&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; output_image.jxl&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -q&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 90&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; --lossless_jpeg=0&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Conversion to &lt;code&gt;.avif&lt;/code&gt;&lt;/h3&gt;&lt;p&gt;There are two main tools: &lt;a href=https://github.com/kornelski/cavif-rs&gt;cavif-rs&lt;/a&gt; and &lt;a href=https://ffmpeg.org/ &gt;ffmpeg&lt;/a&gt;. cavif-rs currently doesn&#39;t support GIFs, so we need to use ffmpeg for them.&lt;/p&gt;&lt;p&gt;To convert a static image to AVIF, using cavif-rs:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;cavif&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; input_image.jpg&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -o&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; output_image.avif&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -Q&lt;/span&gt;&lt;span style=color:#098658;--shiki-dark:#84967A&gt; 90&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -f&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To convert a GIF to AVIF using ffmpeg, you will also need &lt;a href=https://github.com/AOMediaCodec/libavif&gt;libavif&lt;/a&gt;.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;# sudo apt install ffmpeg&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;# sudo apt install libavif-bin&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;# first, from .gif to .y4m&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ffmpeg&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -i&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; input.gif&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -pix_fmt&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; yuv420p&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -f&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; yuv4mpegpipe&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; temp.y4m&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;# then, from .y4m to .avif&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;avifenc&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; temp.y4m&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; output.avif&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=html-rendering-with-fallback tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/modern-image-formats-jxl-and-avif/#html-rendering-with-fallback class=header-anchor&gt;&lt;span&gt;HTML rendering with fallback&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;If you want to use these new formats, but also want to guarantee compatibility with older web browsers, you can use the HTML &lt;code&gt;&amp;lt;picture&gt;&lt;/code&gt; tag.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;html&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;head&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;    &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;title&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;Animated AVIF Example&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;title&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;head&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;body&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;    &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;picture&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;      &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;source&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; type&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;image/avif&quot;&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; srcset&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;my_animation.avif&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;      &amp;lt;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;img&lt;/span&gt;&lt;span style=color:#e50000;--shiki-dark:#6E9BB3&gt; src&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;=&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt;&quot;my_animation.gif&quot;&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;picture&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;  &amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;body&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&amp;lt;/&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#3F74A0&gt;html&lt;/span&gt;&lt;span style=color:maroon;--shiki-dark:#535353&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the browser supports, it will first try to load the picture in AVIF format; else, a GIF will be loaded. The animation below is inside a &lt;code&gt;&amp;lt;picture&gt;&lt;/code&gt; tag — you can verify which format is it by saving the picture.&lt;/p&gt;&lt;p&gt;&lt;picture class=my-4&gt;&lt;source alt=&quot;Curtains moving with the wind&quot; srcset=https://alexandrehtrb.github.io/assets/img/posts/2024_01_curtains.avif type=image/avif&gt;&lt;img alt=&quot;Curtains moving with the wind&quot; src=https://alexandrehtrb.github.io/assets/img/posts/2024_01_curtains.gif&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;Due to the reduced file size of the images, the web pages will load faster.&lt;/p&gt;&lt;h2 id=read-more tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/modern-image-formats-jxl-and-avif/#read-more class=header-anchor&gt;&lt;span&gt;Read more&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;a href=https://tonisagrista.com/blog/2023/jpegxl-vs-avif/ &gt;JPEG XL vs AVIF: A Comparison&lt;/a&gt; (&lt;a href=https://web.archive.org/web/20240121144338/https://tonisagrista.com/blog/2023/jpegxl-vs-avif/ &gt;WebArchive&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://eclipseo.github.io/image-comparison-web/#adventure-with-the-windmills*1:1&amp;AOM_3.1.1=s&amp;JXL_20210715=s&amp;subset1&quot;&gt;Image formats comparison&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=https://siipo.la/blog/whats-the-best-lossless-image-format-comparing-png-webp-avif-and-jpeg-xl&gt;What’s the best lossless image format? Comparing PNG, WebP, AVIF, and JPEG XL&lt;/a&gt; (&lt;a href=https://web.archive.org/web/20240121174347/https://siipo.la/blog/whats-the-best-lossless-image-format-comparing-png-webp-avif-and-jpeg-xl&gt;WebArchive&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;&lt;a href=https://kornel.ski/en/faircomparison&gt;How to compare images fairly&lt;/a&gt; (&lt;a href=https://web.archive.org/web/20240126200642/https://kornel.ski/en/faircomparison&gt;WebArchive&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;&lt;a href=https://cloudinary.com/blog/how_jpeg_xl_compares_to_other_image_codecs&gt;How JPEG XL Compares to Other Image Codecs&lt;/a&gt; (&lt;a href=https://web.archive.org/web/20240121174134/https://cloudinary.com/blog/how_jpeg_xl_compares_to_other_image_codecs&gt;WebArchive&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;&lt;a href=https://www.mdpi.com/2078-2489/8/4/131&gt;The Current Role of Image Compression Standards in Medical Imaging&lt;/a&gt; (&lt;a href=https://web.archive.org/web/20240126221119/https://www.mdpi.com/2078-2489/8/4/131&gt;WebArchive&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;&lt;a href=https://codelabs.developers.google.com/codelabs/avif#0&gt;Serving AVIF images codelab&lt;/a&gt;&lt;/p&gt;&lt;h2 id=images-used-in-this-article tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/modern-image-formats-jxl-and-avif/#images-used-in-this-article class=header-anchor&gt;&lt;span&gt;Images used in this article&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;All taken from Unsplash:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://unsplash.com/photos/black-hole-galaxy-illustration-Oze6U2m1oYU?utm_content=creditShareLink&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Galaxy&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://unsplash.com/photos/teeth-x-ray-KeVKEs1_RDU?utm_content=creditShareLink&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Dental radiography&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://unsplash.com/photos/an-underground-subway-station-with-escalators-and-stairs-hLIi1IU5IU0?utm_content=creditShareLink&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Subway escalators&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Symlinks for multi-repos</title>
    <link href="https://alexandrehtrb.github.io/posts/2024/01/symlinks-for-multi-repos/" />
    <updated>2024-01-19T00:00:00Z</updated>
    <id>https://alexandrehtrb.github.io/posts/2024/01/symlinks-for-multi-repos/</id>
    <content type="html">&lt;h2 id=repeated-files tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/symlinks-for-multi-repos/#repeated-files class=header-anchor&gt;&lt;span&gt;Repeated files&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Tell me: does the file organization below look familiar?&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;&gt; tree C:&#92;MyProjects&#92; /F&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;C:&#92;MyProjects&#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;├──── Repo1&#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          src&#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          .editorconfig&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          lint.xml&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          build.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          runtestcoverage.ps1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;├──── Repo2&#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          src&#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          .editorconfig&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          lint.xml&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          build.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          runtestcoverage.ps1&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│ ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice that there are files with the same name and content in each project directory. Some examples of repeated files are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Code style files:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;.editorconfig&lt;/code&gt; (many languages)&lt;/li&gt;&lt;li&gt;&lt;code&gt;checkstyle.xml&lt;/code&gt; (Java, Android)&lt;/li&gt;&lt;li&gt;&lt;code&gt;.eslintrc&lt;/code&gt; (JavaScript, TypeScript)&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Scripts:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;build.sh&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;runtestcoverage.ps1&lt;/code&gt; (general scripts)&lt;/li&gt;&lt;li&gt;&lt;code&gt;CMakeLists.txt&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;Makefile&lt;/code&gt; (for C/C++ compilation)&lt;/li&gt;&lt;li&gt;&lt;code&gt;Jenkinsfile&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Secrets and app configuration files:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;appsettings.json&lt;/code&gt; (.NET)&lt;/li&gt;&lt;li&gt;&lt;code&gt;Web.config&lt;/code&gt; (ASP NET Framework)&lt;/li&gt;&lt;li&gt;&lt;code&gt;.env&lt;/code&gt; (npm)&lt;/li&gt;&lt;li&gt;others&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you have many repositories with repeated files, it becomes tiresome to change them, because the effort needs to be done for each repository.&lt;/p&gt;&lt;h2 id=pointers%3F tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/symlinks-for-multi-repos/#pointers%3F class=header-anchor&gt;&lt;span&gt;Pointers?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;In programming, there is the concept of pointers — something that points to something else. Usually, we think on memory pointers, that point to a value or structure in RAM memory. However, this concept also exists in file systems: it&#39;s called symbolic links, &lt;strong&gt;&lt;em&gt;symlinks&lt;/em&gt;, files that point to other files.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Symbolic links are a mature technology, that showed as early as in 1960&#39;s computers. They are fully supported on Linux, Mac OSX and Windows, even in older versions.&lt;/p&gt;&lt;h2 id=links tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/symlinks-for-multi-repos/#links class=header-anchor&gt;&lt;span&gt;Links&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;In a file system, each element, file or directory, is represented by an &lt;em&gt;inode&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;An inode of a file is composed by metadata and address in the hard drive. Directory inodes are lists of other inodes.&lt;/p&gt;&lt;p&gt;There are two types of links: &lt;em&gt;hardlinks&lt;/em&gt; and &lt;em&gt;symlinks&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;A &lt;em&gt;&lt;strong&gt;hardlink&lt;/strong&gt;&lt;/em&gt; is when a file points to the same inode as other file. Both access the same content in the disk. When one of these files is deleted, the content of the other file is not lost.&lt;/p&gt;&lt;p&gt;A &lt;em&gt;&lt;strong&gt;symlink&lt;/strong&gt;&lt;/em&gt; is when a file points to another file. In this case, the pointer file depends on the target file to access its content. If the target file is deleted or moved, the symlink becomes invalid.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Symlinks&lt;/em&gt; can have absolute or relative paths.&lt;/p&gt;&lt;p&gt;Example of an absolute path: &lt;code&gt;/home/alexandre/Projects/file.txt&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Example of a relative path: &lt;code&gt;../file.txt&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=language-mermaid&gt;&lt;div class=mermaid&gt;graph TD;
    I(inode)
    A(file.txt)
    AHL(hardlinked_file.txt)
    ASL(symlinked_file.txt)
    A==&gt;I
    AHL==hardlink==&gt;I
    ASL-.symlink.-&gt;A
    style I fill:#f9f,stroke:#333,stroke-width:4px,color:#000
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=symlinks-for-organization-of-files tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/symlinks-for-multi-repos/#symlinks-for-organization-of-files class=header-anchor&gt;&lt;span&gt;Symlinks for organization of files&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Considering the scenario in the beginning of the article, we can unify files of many projects through the use of symlinks.&lt;/p&gt;&lt;p&gt;Inside each repository, let&#39;s create links that will point to files in a Configs folder, located one level above. The Configs folder can become a repository itself, separate from Repo1 and Repo2.&lt;/p&gt;&lt;p&gt;The diagram below shows better. &lt;code&gt;--&gt;&lt;/code&gt; indicates a symlink.&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span&gt;C:&#92;MyProjects&#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;├──── Configs&#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          .editorconfig&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          build.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;├──── Repo1&#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          .editorconfig --&gt; ../Configs/.editorconfig&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          build.sh --&gt; ../Configs/build.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;├──── Repo2&#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          .editorconfig --&gt; ../Configs/.editorconfig&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          build.sh --&gt; ../Configs/build.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│          ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;│ ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On VS Code, symlinks have an arrow icon to the right of the file name.&lt;/p&gt;&lt;img alt=&quot;Symlinks on VS Code&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2024_01_vscode_symlinks.png&gt;&lt;p&gt;The command to create symlinks on Linux and Mac OSX is:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;ln&lt;/span&gt;&lt;span style=color:#00f;--shiki-dark:#9C6650&gt; -s&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; ../Configs/original_file.txt&lt;/span&gt;&lt;span style=color:#a31515;--shiki-dark:#9C6650&gt; symlinked_file.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On Windows command line:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;REM&lt;/span&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt; requires admin elevation&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#00f;--shiki-dark:#417EB1&gt;mklink&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt; symlinked_file.txt ..&#92;Configs&#92;original_file.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On PowerShell:&lt;/p&gt;&lt;pre class=&quot;NomosBlack light-plus shiki shiki-themes&quot; style=background-color:#fff;--shiki-dark-bg:#000000;color:#000;--shiki-dark:#d4d4d4 tabindex=0&gt;&lt;code&gt;&lt;span class=line&gt;&lt;span style=color:green;--shiki-dark:#007E2A&gt;# requires admin elevation&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;span style=color:#795e26;--shiki-dark:#B6B677&gt;New-Item&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt; -&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;ItemType SymbolicLink &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;Path symlinked_file.txt &lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;-&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;Value ..&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;/&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;Configs&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#A5A5A5&gt;/&lt;/span&gt;&lt;span style=color:#000;--shiki-dark:#D4D4D4&gt;original_file.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=line&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=git tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/symlinks-for-multi-repos/#git class=header-anchor&gt;&lt;span&gt;Git&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Git supports symlink files committed in repositories.&lt;/p&gt;&lt;p&gt;On GitHub, they appear with an arrow and name coloured in blue.&lt;/p&gt;&lt;img alt=&quot;Symlinks repo&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2024_01_github_symlink_repo.png&gt;&lt;p&gt;On online navigation and in pull requests, the file content appears as the symlink&#39;s path, either absolute or relative.&lt;/p&gt;&lt;img alt=&quot;Symlinks repo file&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2024_01_github_symlink_file.png&gt;&lt;h2 id=when-should-i-use-this-approach%3F tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/symlinks-for-multi-repos/#when-should-i-use-this-approach%3F class=header-anchor&gt;&lt;span&gt;When should I use this approach?&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Organizing files with symlinks is good in situations with many projects that share many common files.&lt;/p&gt;&lt;p&gt;If there are few files in common, or if there are not too many repos, it&#39;s OK to have repeated files!&lt;/p&gt;&lt;p&gt;In some cases, like pipelines, it&#39;s better to choose other reusability approaches. GitHub Actions, for example, suggests to adopt &lt;a href=https://github.blog/2022-02-10-using-reusable-workflows-github-actions/ &gt;&lt;em&gt;reusable workflows&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Symbolic directories can be a good alternative to Git submodules, in some cases.&lt;/p&gt;&lt;h2 id=important-details tabindex=-1&gt;&lt;a href=https://alexandrehtrb.github.io/posts/2024/01/symlinks-for-multi-repos/#important-details class=header-anchor&gt;&lt;span&gt;Important details&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;If you are using Windows, you need to enable symbolic links during the Git installation:&lt;/li&gt;&lt;/ol&gt;&lt;img alt=&quot;Git for Windows setup Symlinks&quot; class=my-4 src=https://alexandrehtrb.github.io/assets/img/posts/2024_01_git_windows_setup_symlinks.png&gt;&lt;ol start=2&gt;&lt;li&gt;&lt;p&gt;Some file systems do not support symlinks, such as FAT32 and exFAT. These two are commonly found in pen-drives and SD cards.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Symlinks are different from Windows shortcuts. Windows shortcuts are files with the &lt;code&gt;.lnk&lt;/code&gt; extension that can only be opened by Windows Explorer and Desktop.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;</content>
  </entry>
</feed>