<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>alchemmist — Articles</title><link>https://alchemmist.xyz/articles/</link><description>Последние записи в блоге alchemmist</description><generator>Hugo 0.163.3</generator><language>en</language><atom:link href="https://alchemmist.xyz/articles/index.xml" rel="self" type="application/rss+xml"/><lastBuildDate>Wed, 11 Feb 2026 16:02:00 +0300</lastBuildDate><item><title>Typing in Python</title><link>https://alchemmist.xyz/articles/typing-python/</link><pubDate>Wed, 11 Feb 2026 16:02:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/typing-python/</guid><description>This article covers two key questions. Why use typing in Python, a language that lets you write without it? And how do you write typed Python code correctly? We will quickly go through the essential tools so that after reading, you can consciously start writing typed Python programs. It is not that hard.
# Dynamic vs Static So what is typing? For many Python developers, this can feel new, because most classic languages such as C, Java, Rust, and many others were originally designed as statically typed languages. But what does that mean? Let’s look at a small C example:</description><content:encoded><![CDATA[<p>This article covers two key questions. Why use typing in Python, a
language that lets you write without it? And how do you write typed
Python code correctly? We will quickly go through the essential tools
so that after reading, you can consciously start writing typed Python
programs. It is not that hard.</p>

<h2 id="dynamic-vs-static">
  <a class="link" href="#dynamic-vs-static">
    #
  </a>
  Dynamic vs Static
</h2>

<p>So what is typing? For many Python developers, this can feel new,
because most classic languages such as C, Java, Rust, and many others
were originally designed as statically typed languages. But what does
that mean? Let&rsquo;s look at a small C example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">sum</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;%d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="nf">sum</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// printf(&#34;%d\n&#34;, sum(&#34;10&#34;, 20));
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This code works and prints <code>30</code>. But note that the last line is
commented out. If we uncomment it and compile again, we will get an
error log like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plaintext" data-lang="plaintext"><span class="line"><span class="cl">error: passing argument 1 of ‘sum’ makes integer from pointer without cast
</span></span><span class="line"><span class="cl">   10 |     printf(&#34;%d\n&#34;, sum(&#34;10&#34;, 20));
</span></span><span class="line"><span class="cl">      |                        ^~~~
</span></span><span class="line"><span class="cl">      |                        |
</span></span><span class="line"><span class="cl">      |                        char *
</span></span><span class="line"><span class="cl">note: expected ‘int’ but argument is of type ‘char *’
</span></span></code></pre></div><p>The log says that the function parameter expected <code>int</code> but got
<code>char *</code> (<em>for simplicity, think of it as a string</em>). At first glance,
this may not look surprising for Python developers, because this Python
code would also fail:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">sum</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">sum</span><span class="p">(</span><span class="s2">&#34;10&#34;</span><span class="p">,</span> <span class="mi">20</span><span class="p">))</span> <span class="c1"># TypeError</span>
</span></span></code></pre></div><p>So what is the difference? Let&rsquo;s tweak both examples in C and Python,
and call <code>sum</code> with two strings:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">sum</span><span class="p">(</span><span class="s2">&#34;10&#34;</span><span class="p">,</span> <span class="s2">&#34;20&#34;</span><span class="p">))</span> <span class="c1"># &gt; 1020</span>
</span></span></code></pre></div><p>Here we get no error, because polymorphism works and string addition is
valid. But what happens in C?</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;%d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="nf">sum</span><span class="p">(</span><span class="s">&#34;10&#34;</span><span class="p">,</span> <span class="s">&#34;20&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You cannot even compile this program. You get the same error log as
before. Notice how we defined <code>sum</code> in C: we explicitly set input
argument types to <code>int</code>. That means arguments of any other type cannot
be passed into this function. This is static typing. Static typing also
requires a type for each variable and prevents changing variable types
after declaration. In other words, the type is fixed.</p>
<p>The second group is dynamically typed languages: Python, Lua,
JavaScript, and others. In those languages, the variable type is not
strictly fixed and can change during execution.</p>

<h2 id="benefits-of-typing">
  <a class="link" href="#benefits-of-typing">
    #
  </a>
  Benefits of Typing
</h2>

<p>Now to the question: why do we need typing if Python already works well
without it? First, speed. At a low level (<em>whatever representation you
use</em>), types are always needed. If we do not write them explicitly, it
only means someone else does that for us (<em>for example, a virtual
machine</em>), which requires resources. That is reflected in language speed
rankings:</p>
<p><img
    src="/images/pl-rating_hu_96ba15e059292ea.webp"
    width="1600"
    height="1079"
    class="content-img" style="width:900px"
    alt=""
    loading="lazy"
    decoding="async"
  /></p>
<p>In this
<a href="https://github.com/niklas-heer/speed-comparison">rating</a>, Python is at
the bottom. Will typed Python fix that? Unfortunately,
<a href="https://bernsteinbear.com/blog/typed-python/#fnref:simple-annotations">no</a>.
Python was not and still is not a statically typed language. Type
annotations in Python remain optional. You can omit them, and the Python
interpreter does not enforce them at runtime.</p>
<p>This brings us to the second benefit of types: code quality.</p>
<blockquote class="markdown-blockquote">
  <p>&ldquo;The goal of typing in Python is to help development tools find
errors in Python code bases through static analysis, without running
code tests.&rdquo;</p>
<p>Luciano Ramalho, &ldquo;Fluent Python&rdquo;</p>

</blockquote>
<p>Extending this idea, typing goals are:</p>
<ul>
<li>Early error detection, before runtime and before production failures.</li>
<li>&ldquo;Test extraction&rdquo;: correct typing can reduce the number of tests,
which are often harder to write and maintain than types. Tests can
then focus on business logic, not primitive mismatches.</li>
<li>Better readability: <a href="https://peps.python.org/pep-0020/">PEP 20</a>
says &ldquo;Explicit is better than implicit.&rdquo; When reading code, function
signatures are often enough without diving into implementation.</li>
<li>Better IDE workflow with more hints and warnings.</li>
<li>Better architecture quality: types force cleaner abstractions.</li>
</ul>

<h2 id="how-to-write-typed-code">
  <a class="link" href="#how-to-write-typed-code">
    #
  </a>
  How to Write Typed Code
</h2>

<p>Before code, let&rsquo;s separate three important concepts: interface,
abstract class, and protocol. What is the difference?</p>
<ul>
<li><strong>Interface</strong> is a class where all methods are abstract, with no
implementation details.</li>
<li><strong>Abstract class</strong> is a class with both abstract and implemented
methods.</li>
<li><strong>Protocol</strong> is an implicit interface.</li>
</ul>
<p>The first two are straightforward. Let&rsquo;s focus on the last one. In
Python, an interface pattern is usually implemented through inheritance:
a class implementing an interface inherits from that interface class. A
class implementing a protocol does not have to inherit from it and may
not even know about it.</p>

<h3 id="primitives">
  <a class="link" href="#primitives">
    ##
  </a>
  Primitives
</h3>

<p>Let&rsquo;s finally look at how to write typed code. Start with a simple
function that repeats a string <code>n</code> times.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">multi_string</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">string</span> <span class="o">*</span> <span class="n">n</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">multi_string</span><span class="p">(</span><span class="s2">&#34;cat&#34;</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span> <span class="c1"># &gt; catcatcat</span>
</span></span></code></pre></div><p>This function takes a string and a number and returns a string built by
concatenating the original string with itself <code>n</code> times. Now type it:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">multi_string</span><span class="p">(</span><span class="n">string</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">string</span> <span class="o">*</span> <span class="n">n</span>
</span></span></code></pre></div><p>Syntax is simple: input parameter types go after a colon, output type
goes after an arrow. Your IDE can now highlight errors if inputs are
wrong or if returned values are handled incorrectly.</p>
<p><img src="/images/typing-demo-1.gif" class="content-img" style="width:700px" alt="" loading="lazy" decoding="async" /></p>
<p>You can annotate all common primitives this way:
<code>str</code>, <code>int</code>, <code>bytes</code>, <code>float</code>, <code>Decimal</code>, <code>bool</code>.</p>

<h3 id="union-types">
  <a class="link" href="#union-types">
    ##
  </a>
  Union Types
</h3>

<p>In real code there are more complex cases where a function should accept
multiple types, but not arbitrary ones. In those cases use unions:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">normalize</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">data</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&#34;utf-8&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">data</span>
</span></span></code></pre></div><p>Here <code>normalize</code> accepts either a string or bytes and always returns a
UTF-8 string. With <code>union</code> (<code>|</code>), you can list multiple types, but you
should use this carefully. If you feel like writing a long union of ten
types, pause and reconsider. We will cover ways to handle such cases
below.</p>
<p>Unions are also valid for return types, but mostly for optional
results. Example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">parse_int</span><span class="p">(</span><span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="n">value</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
</span></span></code></pre></div><p>This means the function result is optional. It may return <code>int</code>, or may
not return one if parsing fails. But annotating returns as <code>int | str</code>
or other unrelated combinations is usually bad practice. It becomes
unclear how to process the result. In practice, return either a concrete
type with known methods/attributes, or <code>None</code>. Breaking this rule tends
to complicate code.</p>

<h3 id="collection-specification">
  <a class="link" href="#collection-specification">
    ##
  </a>
  Collection Specification
</h3>

<p>Besides primitives, you can and should annotate collections. Avoid plain
<code>data: list</code>; specify element types too. Use square brackets:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">format_user</span><span class="p">(</span><span class="n">user</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">name</span><span class="p">,</span> <span class="n">score</span> <span class="o">=</span> <span class="n">user</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">score</span><span class="si">}</span><span class="s2"> points&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">average</span><span class="p">(</span><span class="n">values</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">float</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">values</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="n">values</span><span class="p">)</span> <span class="o">/</span> <span class="nb">len</span><span class="p">(</span><span class="n">values</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">total_count</span><span class="p">(</span><span class="n">counters</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="n">counters</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
</span></span></code></pre></div><p>Of course, this does not cover all production scenarios. In
<a href="/articles/typing-python/#typeddict">TypedDict</a>, <a href="/articles/typing-python/#namedtuple">NamedTuple</a>, and
<a href="/articles/typing-python/#dataclass">Dataclass</a>, we extend this toolkit.</p>

<h3 id="mapping-and-mutablemapping">
  <a class="link" href="#mapping-and-mutablemapping">
    ##
  </a>
  Mapping and MutableMapping
</h3>

<p><code>Mapping</code> and <code>MutableMapping</code> are abstract base classes for dict-like
structures. <code>Mapping</code> guarantees read-only behavior (keys, values,
iteration), while <code>MutableMapping</code> says the object is mutable.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Mapping</span><span class="p">,</span> <span class="n">MutableMapping</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">read_config</span><span class="p">(</span><span class="n">cfg</span><span class="p">:</span> <span class="n">Mapping</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">cfg</span><span class="p">[</span><span class="s2">&#34;DATABASE_URL&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">patch_config</span><span class="p">(</span><span class="n">cfg</span><span class="p">:</span> <span class="n">MutableMapping</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">cfg</span><span class="p">[</span><span class="s2">&#34;DEBUG&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;1&#34;</span>
</span></span></code></pre></div><p>If a function only reads data, use <code>Mapping</code>. If it mutates data, use
<code>MutableMapping</code>. This is a small but important signal for readers and
type checkers.</p>

<h3 id="namedtuple">
  <a class="link" href="#namedtuple">
    ##
  </a>
  NamedTuple
</h3>

<p>When you need a fixed set of fields while keeping tuple behavior,
<code>NamedTuple</code> is useful. It is immutable and indexable, but also lets you
access fields by name.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">NamedTuple</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">User</span><span class="p">(</span><span class="n">NamedTuple</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="nb">id</span><span class="p">:</span> <span class="nb">int</span>
</span></span><span class="line"><span class="cl">    <span class="n">username</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">    <span class="n">score</span><span class="p">:</span> <span class="nb">int</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">print_user</span><span class="p">(</span><span class="n">user</span><span class="p">:</span> <span class="n">User</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">user</span><span class="o">.</span><span class="n">username</span><span class="si">}</span><span class="s2"> (</span><span class="si">{</span><span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="si">}</span><span class="s2">) = </span><span class="si">{</span><span class="n">user</span><span class="o">.</span><span class="n">score</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span></code></pre></div><p><code>NamedTuple</code> is good for compact data structures that should not change
after creation. If you need mutability and richer behavior, prefer
<code>dataclass</code> or a regular class.</p>

<h3 id="typeddict">
  <a class="link" href="#typeddict">
    ##
  </a>
  TypedDict
</h3>

<p>If your structure is a dictionary and you want typed keys and values,
use <code>TypedDict</code>. It describes dictionary shape and works at static
analysis level.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypedDict</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">User</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="nb">id</span><span class="p">:</span> <span class="nb">int</span>
</span></span><span class="line"><span class="cl">    <span class="n">username</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">    <span class="n">email</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">send_email</span><span class="p">(</span><span class="n">user</span><span class="p">:</span> <span class="n">User</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span></code></pre></div><p>This is especially useful when data comes from JSON or another dynamic
source but you still want a strict key contract. If some keys are
optional, define that explicitly to keep type checks meaningful.</p>

<h3 id="dataclass">
  <a class="link" href="#dataclass">
    ##
  </a>
  Dataclass
</h3>

<p><code>dataclass</code> is a convenient way to define a data container with
initializer, comparisons, and readable <code>repr</code>. This class is mutable by
default and works well for domain objects and DTOs.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">User</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">id</span><span class="p">:</span> <span class="nb">int</span>
</span></span><span class="line"><span class="cl">    <span class="n">username</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">    <span class="n">email</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">normalize</span><span class="p">(</span><span class="n">user</span><span class="p">:</span> <span class="n">User</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">User</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">user</span><span class="o">.</span><span class="n">username</span> <span class="o">=</span> <span class="n">user</span><span class="o">.</span><span class="n">username</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">user</span>
</span></span></code></pre></div><p><code>dataclass</code> is a good fit when you need mutable structure and clear data
modeling. If an object must be immutable, use
<code>@dataclass(frozen=True)</code>.</p>

<h3 id="enum">
  <a class="link" href="#enum">
    ##
  </a>
  Enum
</h3>

<p><code>Enum</code> helps define a closed set of values. This is useful when a field
has a strict list of allowed options and you do not want random strings
in your code.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">enum</span> <span class="kn">import</span> <span class="n">Enum</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Status</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">NEW</span> <span class="o">=</span> <span class="s2">&#34;new&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">DONE</span> <span class="o">=</span> <span class="s2">&#34;done&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">FAILED</span> <span class="o">=</span> <span class="s2">&#34;failed&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">is_done</span><span class="p">(</span><span class="n">status</span><span class="p">:</span> <span class="n">Status</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">status</span> <span class="ow">is</span> <span class="n">Status</span><span class="o">.</span><span class="n">DONE</span>
</span></span></code></pre></div><p>This approach is practical for statuses, roles, flags, modes, and other
enumerable domain values.</p>

<h3 id="custom-classes">
  <a class="link" href="#custom-classes">
    ##
  </a>
  Custom Classes
</h3>

<p>The type system can specify not only primitives but also your own or
library classes. For example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">User</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">id</span><span class="p">:</span> <span class="nb">int</span>
</span></span><span class="line"><span class="cl">    <span class="n">username</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">    <span class="n">email</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">    <span class="n">friends</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">User</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">hand_shake</span><span class="p">(</span><span class="n">user1</span><span class="p">:</span> <span class="n">User</span><span class="p">,</span> <span class="n">user2</span><span class="p">:</span> <span class="n">User</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">user1</span><span class="o">.</span><span class="n">friends</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">user2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">user2</span><span class="o">.</span><span class="n">friends</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">user1</span><span class="p">)</span>
</span></span></code></pre></div>
<h3 id="abstract-classes">
  <a class="link" href="#abstract-classes">
    ##
  </a>
  Abstract Classes
</h3>

<p>Python has an excellent module, <code>collections.abc</code>. It already defines a
large set of abstract classes that cover most practical needs. They are
useful when you want to describe behavior, not a concrete
implementation. What is available there?</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">ABCMeta</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">AsyncGenerator</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">AsyncIterable</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">AsyncIterator</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Awaitable</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Buffer</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">ByteString</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Callable</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Collection</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Container</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Coroutine</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">EllipsisType</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">FunctionType</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Generator</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">GenericAlias</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Hashable</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">ItemsView</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Iterable</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Iterator</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">KeysView</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Mapping</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">MappingView</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">MutableMapping</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">MutableSequence</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">MutableSet</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Reversible</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Sequence</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Set</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">Sized</span>
</span></span><span class="line"><span class="cl"><span class="n">collections</span><span class="o">.</span><span class="n">abc</span><span class="o">.</span><span class="n">ValuesView</span>
</span></span></code></pre></div><p>As you can see, there are many abstract classes. Most describe a
property of a collection. Using them in annotations lets you express
wider polymorphic input boundaries for your functions:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Iterable</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">total</span><span class="p">(</span><span class="n">values</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="nb">int</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="n">values</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">total</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">total</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">total</span><span class="p">({</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">})</span>
</span></span></code></pre></div><p>Sometimes you still see imports from <code>typing</code> like
<code>from typing import Iterable, Sequence</code>. In practice, those are
re-exports from <code>collections.abc</code>. Today it is better to import these
ABCs directly from <code>collections.abc</code>.</p>

<h3 id="sequence-and-iterable">
  <a class="link" href="#sequence-and-iterable">
    ##
  </a>
  Sequence and Iterable
</h3>

<p>These two are often confused. <code>Iterable</code> only guarantees that an object
can be iterated in a loop. No indexing, length, or ordering is
promised. <code>Sequence</code> guarantees iteration plus indexing and length, that
is <code>__getitem__</code> and <code>__len__</code>. This leads to a practical difference in
what operations are safe.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Iterable</span><span class="p">,</span> <span class="n">Sequence</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">sum_any</span><span class="p">(</span><span class="n">values</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="nb">int</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">total</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">values</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">total</span> <span class="o">+=</span> <span class="n">v</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">total</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">head</span><span class="p">(</span><span class="n">values</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="nb">int</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span></code></pre></div><p><code>sum_any</code> accepts a list, tuple, or generator. <code>head</code> cannot accept a
generator, because it has no indexing and you cannot do <code>values[0]</code>.
So, if you only need iteration, use <code>Iterable</code>; if you rely on indexing
or length, use <code>Sequence</code>.</p>

<h3 id="callable">
  <a class="link" href="#callable">
    ##
  </a>
  Callable
</h3>

<p><code>Callable</code> is used when a function accepts another function. This is
especially important for callbacks, event handlers, and higher-order
functions.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Callable</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">apply</span><span class="p">(</span><span class="n">values</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">],</span> <span class="n">fn</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="nb">int</span><span class="p">],</span> <span class="nb">int</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">[</span><span class="n">fn</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">values</span><span class="p">]</span>
</span></span></code></pre></div><p>If the signature is unknown in advance, you can use
<code>Callable[..., ReturnType]</code>, but this should be a last resort.</p>

<h3 id="generics">
  <a class="link" href="#generics">
    ##
  </a>
  Generics
</h3>

<p>Generics are parameterized types. In simple terms, these are types that
accept other types. This matters when you want to preserve the relation
between input and output instead of losing it to <code>Any</code>. For example,
<code>first</code> returns the same item type as inside the input collection:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Sequence</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypeVar</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&#34;T&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">first</span><span class="p">(</span><span class="n">items</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">items</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span></code></pre></div><p>Without generics, you would write <code>Sequence[Any]</code> and lose output type.
With generics, the analyzer knows that if input is <code>Sequence[str]</code>, the
result is <code>str</code>. This is especially important for collections, factories,
and repositories where one implementation handles multiple types.</p>
<p>It is also useful to know that <code>TypeVar</code> has a <code>bound</code> parameter that
restricts which types can be used in a generic:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Hashable</span><span class="p">,</span> <span class="n">Iterable</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypeVar</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">HashableT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&#34;HashableT&#34;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="n">Hashable</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">mode</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="n">HashableT</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">HashableT</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span></code></pre></div>
<h3 id="literal">
  <a class="link" href="#literal">
    ##
  </a>
  Literal
</h3>

<p><code>Literal</code> lets you fix exact allowed values, not just a base type. This
is useful when a parameter has a closed set of modes, statuses, or keys.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Literal</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">export_report</span><span class="p">(</span><span class="nb">format</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&#34;csv&#34;</span><span class="p">,</span> <span class="s2">&#34;json&#34;</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">bytes</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span></code></pre></div><p>The signature above defines the contract clearly: no third format
exists here. This makes APIs clearer and lets type checkers catch typos
such as <code>&quot;jsno&quot;</code> before runtime.</p>

<h3 id="static-analyzers">
  <a class="link" href="#static-analyzers">
    ##
  </a>
  Static Analyzers
</h3>

<p>Now it is time to discuss what makes typing practical in Python:
static analyzers. They read annotations, compare them with actual code,
and report problems before runtime.</p>
<ul>
<li><code>mypy</code> is the classic static type checker for gradual typing.
Strength: plugin ecosystem and precise per-module strictness tuning.
Weakness: without tuning it can be either too soft or too noisy.</li>
<li><code>pyright</code> is a fast and clear checker.
Strength: good diagnostics and fast feedback.
Weakness: plugin-style extensibility is weaker than in <code>mypy</code>.</li>
<li><code>pyrefly</code> is a new fast Rust analyzer.
Strength: high speed and LSP integration.
Weakness: still young, so some behavior may change.</li>
<li><code>ty</code> is a new Rust tool by Astral (currently beta).
Strength: speed and modern architecture.
Weakness: pre-release stage; feature set is still catching up to
mature checkers.</li>
</ul>
<p>You can install and run them with <code>uv</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">uv tool install mypy
</span></span><span class="line"><span class="cl">uv tool install pyright
</span></span><span class="line"><span class="cl">uv tool install pyrefly
</span></span><span class="line"><span class="cl">uv tool install ty
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">uvx mypy .
</span></span><span class="line"><span class="cl">uvx pyright .
</span></span><span class="line"><span class="cl">uvx pyrefly check
</span></span><span class="line"><span class="cl">uvx ty check
</span></span></code></pre></div><p>Here is a business-oriented example with intentional typing mistakes:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">NewType</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">UserId</span> <span class="o">=</span> <span class="n">NewType</span><span class="p">(</span><span class="s2">&#34;UserId&#34;</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">User</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">id</span><span class="p">:</span> <span class="n">UserId</span>
</span></span><span class="line"><span class="cl">    <span class="n">email</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">    <span class="n">is_active</span><span class="p">:</span> <span class="nb">bool</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">discount</span><span class="p">(</span><span class="n">total</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">percent</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">total</span> <span class="o">-</span> <span class="n">total</span> <span class="o">*</span> <span class="p">(</span><span class="n">percent</span> <span class="o">/</span> <span class="mi">100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">send_invoice</span><span class="p">(</span><span class="n">user</span><span class="p">:</span> <span class="n">User</span><span class="p">,</span> <span class="n">amount</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="n">user</span><span class="o">.</span><span class="n">is_active</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;invoice for </span><span class="si">{</span><span class="n">user</span><span class="o">.</span><span class="n">email</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">amount</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">main</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">42</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="mi">123</span><span class="p">,</span> <span class="n">is_active</span><span class="o">=</span><span class="s2">&#34;yes&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">total</span> <span class="o">=</span> <span class="n">discount</span><span class="p">(</span><span class="s2">&#34;1000&#34;</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">send_invoice</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="s2">&#34;500&#34;</span><span class="p">)</span>
</span></span></code></pre></div><p>Running <code>pyright</code> on this file will produce messages roughly like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plaintext" data-lang="plaintext"><span class="line"><span class="cl">error: Type &#34;float&#34; is not assignable to return type &#34;int&#34;
</span></span><span class="line"><span class="cl">error: Type &#34;None&#34; is not assignable to return type &#34;str&#34;
</span></span><span class="line"><span class="cl">error: &#34;Literal[42]&#34; is not assignable to &#34;UserId&#34;
</span></span><span class="line"><span class="cl">error: &#34;Literal[123]&#34; is not assignable to &#34;str&#34;
</span></span><span class="line"><span class="cl">error: &#34;Literal[&#39;yes&#39;]&#34; is not assignable to &#34;bool&#34;
</span></span><span class="line"><span class="cl">error: &#34;Literal[&#39;1000&#39;]&#34; is not assignable to &#34;int&#34;
</span></span><span class="line"><span class="cl">error: &#34;Literal[&#39;500&#39;]&#34; is not assignable to &#34;int&#34;
</span></span></code></pre></div><p>What matters in this output:</p>
<ul>
<li>Errors in <code>discount</code> and <code>send_invoice</code> show function contract
violations: the signature promises one thing, implementation does
another.</li>
<li>Errors in <code>main</code> show boundary-layer issues (input/DTO) passing
wrong types into domain logic.</li>
<li>The <code>UserId</code> error demonstrates why <code>NewType</code> is useful in business
code: a user identifier cannot be accidentally replaced by a plain
<code>int</code> without an explicit decision.</li>
</ul>

<h3 id="stub-files-pyi">
  <a class="link" href="#stub-files-pyi">
    ##
  </a>
  Stub Files (.pyi)
</h3>

<p>Sometimes you want typing for code you cannot or should not edit.
Examples: generated code, third-party library code, or your own module
where you do not want to mix typing and implementation. That is what
stub files with <code>.pyi</code> extension are for.</p>
<p>A <code>.pyi</code> file contains type signatures only and no implementation.
Static analyzers look for these files near source code or in dedicated
<code>types-*</code> packages. Example:</p>
<p><code>calc.py</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
</span></span></code></pre></div><p><code>calc.pyi</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span> <span class="o">...</span>
</span></span></code></pre></div><p>This way you can keep typing separate from implementation, sometimes
even without access to source code.</p>

<h3 id="typealias">
  <a class="link" href="#typealias">
    ##
  </a>
  TypeAlias
</h3>

<p>When a type gets complex, move it into an alias to keep signatures
readable. This is especially useful for business terms like <code>UserId</code>,
<code>Currency</code>, or <code>Payload</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypeAlias</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">UserId</span><span class="p">:</span> <span class="n">TypeAlias</span> <span class="o">=</span> <span class="nb">int</span>
</span></span><span class="line"><span class="cl"><span class="n">Payload</span><span class="p">:</span> <span class="n">TypeAlias</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">float</span><span class="p">]</span>
</span></span></code></pre></div><p>Then you can write:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">send</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="n">UserId</span><span class="p">,</span> <span class="n">payload</span><span class="p">:</span> <span class="n">Payload</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span></code></pre></div><p>In Python 3.12+, you can use the <code>type</code> statement instead:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nb">type</span> <span class="n">UserId</span> <span class="o">=</span> <span class="nb">int</span>
</span></span><span class="line"><span class="cl"><span class="nb">type</span> <span class="n">Payload</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">float</span><span class="p">]</span>
</span></span></code></pre></div><p>This is the same alias, just shorter and easier to read.</p>

<h3 id="typealias-vs-newtype">
  <a class="link" href="#typealias-vs-newtype">
    ##
  </a>
  TypeAlias vs NewType
</h3>

<p><code>TypeAlias</code> is just a type synonym, it does not create a new type.
<code>NewType</code> creates a distinct type at static-checking level, even though
at runtime it is just a wrapper function. This is useful when you have
logically different values of the same base type, for example <code>UserId</code>
and <code>OrderId</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">NewType</span><span class="p">,</span> <span class="n">TypeAlias</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">UserId</span><span class="p">:</span> <span class="n">TypeAlias</span> <span class="o">=</span> <span class="nb">int</span>
</span></span><span class="line"><span class="cl"><span class="n">OrderId</span> <span class="o">=</span> <span class="n">NewType</span><span class="p">(</span><span class="s2">&#34;OrderId&#34;</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_user</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="n">UserId</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_order</span><span class="p">(</span><span class="n">order_id</span><span class="p">:</span> <span class="n">OrderId</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span></code></pre></div><p><code>UserId</code> and <code>int</code> are treated as the same type. <code>OrderId</code> is not
compatible with <code>int</code> without explicit conversion.</p>

<h2 id="how-to-use-typing-correctly">
  <a class="link" href="#how-to-use-typing-correctly">
    #
  </a>
  How to Use Typing Correctly
</h2>

<p>Set the right expectation first. Like tests, the purpose of types is to
<strong>fail</strong> when the code is wrong. If they never fail, they are not doing
useful work. The less forgiving your typing setup is, the better it
protects your code. Strict typing (<em>like strict tests</em>) catches bugs,
but only if checks can actually fail.</p>
<p>Writing truly correct typed code is hard. It is a separate skill that
grows the same way architecture and testing skills grow. So start small
and increase strictness gradually.</p>

<h3 id="returning-none">
  <a class="link" href="#returning-none">
    ##
  </a>
  Returning <code>None</code>
</h3>

<p>Also consider the case where a function returns nothing:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">print_weather</span><span class="p">(</span><span class="n">weather</span><span class="p">:</span> <span class="n">Weather</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Weather:&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">date</span><span class="p">,</span> <span class="n">data</span> <span class="ow">in</span> <span class="n">weather</span><span class="o">.</span><span class="n">by_days</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="n">date</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="se">\t</span><span class="si">{</span><span class="n">data</span><span class="o">.</span><span class="n">temperature</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="se">\t</span><span class="si">{</span><span class="n">data</span><span class="o">.</span><span class="n">humidity</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="se">\t</span><span class="si">{</span><span class="n">data</span><span class="o">.</span><span class="n">wind_speed</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;========&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">tmp</span> <span class="o">=</span> <span class="n">print_weather</span><span class="p">(</span><span class="n">Weather</span><span class="p">())</span> <span class="o">+</span> <span class="mi">1</span>
</span></span></code></pre></div><p>In Python, if a function has no <code>return</code>, it returns <code>None</code>. Static
analyzers know this too. For example, <code>pyright</code> on this intentionally
broken code will show:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plaintext" data-lang="plaintext"><span class="line"><span class="cl">error:
</span></span><span class="line"><span class="cl">    Operator &#34;+&#34; not supported for types &#34;None&#34; and &#34;Literal[1]&#34;
</span></span></code></pre></div><p>This shows that <code>pyright</code> understands the return type as <code>None</code>. Does
that mean you can skip return annotations? No. First,
<a href="https://peps.python.org/pep-0020/">PEP 20</a> says explicit is better
than implicit. Second, consider developer experience (DX) in Python. Everyone
knows typing is optional, so missing return annotation is ambiguous.
When you see a function signature without return type, you cannot tell
whether the author skipped typing or the function really returns <code>None</code>.
You resolve that only by reading implementation details, which slows
code navigation.</p>

<h3 id="function-input-vs-output">
  <a class="link" href="#function-input-vs-output">
    ##
  </a>
  Function Input vs Output
</h3>

<p>Continuing the return-type topic: avoid using abstract classes from
<code>collections.abc</code>, or custom abstract classes, for function return
types. They are better suited for input types where you want broad
polymorphism. Return values should be concrete so it is clear how to
use the result.</p>





<blockquote class="markdown-alert markdown-alert--important">
  <div class="markdown-alert__title">
    
      <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"/></svg>
    

    
      Important
    
  </div>

  <p>A function should be more explicit about what concrete type it
returns than what it accepts.</p>
</blockquote>
<br>
<hr>
<br>
<p>If you want to go deeper, here are useful resources to configure your
tools and understand Python typing in detail:</p>
<ul>
<li><a href="https://fastapi.tiangolo.com/python-types/#type-hints-with-metadata-annotations">FastAPI type hints guide (helpful for web
developers)</a></li>
<li><a href="https://realpython.com/python-type-checking/">RealPython, Type Checking
Guide</a></li>
<li><a href="https://python-type-challenges.zeabur.app/">Exercises</a></li>
</ul>
]]></content:encoded><category>python</category><category>eosp</category></item><item><title>How to contribute</title><link>https://alchemmist.xyz/articles/how-we-contribute/</link><pubDate>Wed, 11 Feb 2026 12:21:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/how-we-contribute/</guid><description>This is a short beginner’s guide on how to work with open source within GitHub flow practices. All examples will use the GitHub platform, but other repository hosting services that provide the necessary functionality to implement GitHub flow can also be used. Here you can find a classic way to contribute to almost any project, as well as learn a few tips and hacks.
So, where does any contribution begin? Ideally, with a problem. A problem can be called anything, including a lack of new features, missing or incomplete documentation pages on a specific topic, some question, or simply trivial bugs that exist everywhere. You personally will not confuse a problem with anything else, because it will be accompanied by an itchy feeling that “something is annoying.” But will this be a problem for other users and developers? In order to understand this and synchronize your perception with the team’s perception, an issue exists.</description><content:encoded><![CDATA[<p>This is a short beginner’s guide on how to work with open source
within GitHub flow practices. All examples will use the GitHub
platform, but other repository hosting services that provide the
necessary functionality to implement GitHub flow can also be
used. Here you can find a classic way to contribute to almost any
project, as well as learn a few tips and hacks.</p>
<p>So, where does any contribution begin? Ideally, with a problem.
A problem can be called anything, including a lack of new
features, missing or incomplete documentation pages on a specific
topic, some question, or simply trivial bugs that exist
everywhere. You personally will not confuse a problem with
anything else, because it will be accompanied by an itchy feeling
that “something is annoying.” But will this be a problem for
other users and developers? In order to understand this and
synchronize your perception with the team’s perception, an issue
exists.</p>





<blockquote class="markdown-alert markdown-alert--caution">
  <div class="markdown-alert__title">
    
      <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"/></svg>
    

    
      CONTRIBUTION.md
    
  </div>

  <p>Every project has its own established rules on how to
participate in it. These rules are described either in
<code>README.md</code> in a separate “Contribution” paragraph, or in
a special <code>CONTRIBUTION.md</code> file. Be sure to read it at the
very beginning. This file has the highest priority. That is,
even if you understand that some practices deviate from the
correct scheme that we will consider below, you should still
follow them. Some large projects, such as <code>Postgres</code> or
<code>linux-kernel</code>, still work entirely via mailing lists. One
should respect the traditions that have formed in the
repository, even if they now look like legacy.</p>
</blockquote>

<h2 id="1-issue">
  <a class="link" href="#1-issue">
    #
  </a>
  1. Issue
</h2>

<p>An issue is a ticket that is stored in the repository. Anyone who
comes to the repository can create it. But I recommend that
before rushing to describe your problem, you make several
attempts to search for similar issues, so as not to burden the
repository maintainers with unnecessary work. Let’s see how this
can be done:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">gh issue list --search <span class="s2">&#34;app crashed&#34;</span>
</span></span></code></pre></div><blockquote class="markdown-blockquote">
  <p>This and all further examples will use the official <code>gh</code>
utility. It allows you to perform all basic GitHub operations
from the console. I recommend using it for simple operations to
speed up your workflow.</p>

</blockquote>
<p>The <code>search</code> parameter allows you to add various search filters
directly inside it. Let’s try to add them:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">gh issue list --search <span class="s2">&#34;app crashed is:open label:bug created:&gt;2024-01-01&#34;</span>
</span></span></code></pre></div><p>It is quite possible, especially in large projects, that this
will allow you to find an already created ticket for your problem
and even find a solution or answer in it. If not, then do not
hesitate to open a new issue. The following scheme will help
structure it in the best way:</p>
<pre class="mermaid">
  graph LR
    A[Excepted] ---&gt; B(&#34;Action (run/click/etc)&#34;)
    B ---&gt; C[Got]
</pre>

<p>In large projects, there are issue templates that will help you
format an issue according to the standards adopted in that
project. You can create an issue with the command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">gh issue create
</span></span></code></pre></div><p>Another excellent practice is providing a Docker image in which
the entire environment is configured and the problem is
guaranteed to be reproducible. Or at least provide a log.
A professional approach would also be to localize the problem as
much as possible. For example, you received an error in the
following file:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">fruits</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">logistic</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">a</span> <span class="o">=</span> <span class="n">fruits</span><span class="o">.</span><span class="n">Apple</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">basket</span> <span class="o">=</span> <span class="n">fruits</span><span class="o">.</span><span class="n">MakeBasket</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">basket</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">logistic</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">basket</span><span class="p">)</span>
</span></span></code></pre></div><p>Of course, you could write exactly this in the issue. But it
would be even better to independently experiment with this code
and understand what exactly is wrong. For example, check whether
the apple was successfully added to the basket:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">basket</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">basket</span><span class="o">.</span><span class="n">content</span><span class="p">())</span>
</span></span></code></pre></div><p>Perhaps the problem is that we are trying to send an empty
basket, which would mean a bug in the <code>put</code> method. Or perhaps
the problem is in the <code>send</code> method after all. In this way, we
cut off the unnecessary, leaving the essence of the problem in
the issue message.</p>
<p>Remember that even the fact of successfully creating an issue—for
example, proposing a valuable feature or discovering a real bug
or vulnerability—is already a contribution to the project, and
that is already a success. A failure, on the other hand, would be
creating a duplicate issue or overloading maintainers with
unnecessary context.</p>

<h2 id="2-fork">
  <a class="link" href="#2-fork">
    #
  </a>
  2. Fork
</h2>

<p>When you understand which problem you are solving and are
convinced that it is really a problem, you can move on to solving
it. To do this, you should first fork the repository. This will
be valuable support for you if, for example, you are testing CI
or simply getting far ahead of the original repository, and it
will also allow you to send pull requests, since you most likely
do not have permission to make changes to the original
repository:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">gh repo fork &lt;OWNER&gt;/&lt;REPO&gt;
</span></span></code></pre></div><p>After cloning the fork locally, make changes in a separate
branch, which it will be more convenient to name after the issue
number you are trying to close. Why? Because in a short, concise
branch name it is <strong>far</strong> from always possible to express the
essence of the problem, which may have taken several months of
discussion in the ticket. Therefore, it is much more convenient
to simply refer to it by the issue number:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">git switch -c <span class="m">42</span>
</span></span></code></pre></div><p>In GitHub flow, we do not create a complex branch structure where
each branch has its own meaning. Instead, we have a master branch
into which only changes that have passed all checks are merged.
These changes come there from many so-called feature branches,
which we propose to tie to specific issues. And from time to
time, we release a version from the master branch. As a result,
we get a fairly concise structure:</p>
<pre class="mermaid">
  %%{init: {
  &#34;gitGraph&#34;: {
    &#34;tagLabelColor&#34;: &#34;#ffffff&#34;,
    &#34;tagLabelBackground&#34;: &#34;#d73a49&#34;
  }
}}%%
gitGraph
    commit
    commit
    branch &#34;42&#34;
    checkout &#34;42&#34;
    commit
    commit
    checkout main
    merge &#34;42&#34;
    commit tag: &#34;🚩 v1.1.23&#34;

    branch &#34;44&#34;
    checkout &#34;44&#34;
    commit
    commit
    commit
    checkout main
    merge &#34;44&#34;
    commit tag: &#34;🚩 v1.2.0&#34;
</pre>

<p>Also, do not forget to synchronize your <code>fork</code> so as not to lose
connection with the original project:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">gh repo sync &lt;your-username&gt;/&lt;fork-repo&gt; --branch main
</span></span></code></pre></div>
<h2 id="3-pull-request">
  <a class="link" href="#3-pull-request">
    #
  </a>
  3. Pull request
</h2>

<p>When the changes are made and committed, you can send a pull
request. The most convenient way is to simply stay on your branch
and run the command below. <code>gh</code> will form a suitable pull request
itself:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">gh pr create
</span></span></code></pre></div><p>After creating the PR, checks may automatically start if CI is
configured in the repository. And this is great. Because checks
simplify and speed up the review process. You can immediately
see, for example, that your code does not pass style checks, or
that you did not write tests for your code and because of this
the code coverage failed. Do not ignore this, but make new
commits in the same branch, and after pushing them they will
automatically be added to the PR and the checks will be
restarted. The repository maintainer will not even begin
reviewing your PR until all checks in it turn green. You can
check the status of the pull request with the command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">gh pr status
</span></span></code></pre></div><p>Also try to make a neat commit history in the pull request to
simplify the review process.
<a href="https://www.geeksforgeeks.org/git/git-squash/">Squash</a> commits
will help you with this.</p>
<p>When you have broken through all automated checks, do not
hesitate to contact the repository architect and ask for
a review. He will either review your PR himself or delegate it to
someone from the team. On GitHub, this is done simply via a tag:
<code>@username</code>. Often, notifications that a new pull request has
arrived may be disabled, and moreover, the architect will not
know when you have made all the fixes to pass CI. Therefore,
modesty here may lead to the fact that your pull request will
simply not be seen by anyone. This, by the way, also applies to
issues.</p>
<p>If you understand that your pull request completely closes the
issue you were solving, then in the PR messages you can specify
<code>Close #49</code>, and then the issue will be automatically closed
after the pull request is merged.</p>

<h2 id="4-merge">
  <a class="link" href="#4-merge">
    #
  </a>
  4. Merge
</h2>

<p>So, when you have passed all automated checks and manual review,
your code will get into the master branch of the repository, and
you can consider yourself a full-fledged contributor to this
project. Keep it up!</p>
<p>Also pay attention to an interesting practice that, in my
opinion, is very professional. Imagine that you discovered and
reported some bug in an issue. This is already a contribution to
the repository. Next, it is proposed to create a pull request in
which you write a test that reproduces this bug. The test, of
course, will fail. But you send the pull request, thereby adding
this test in a disabled state to the codebase. You can also leave
a <code>TODO</code> tag. And this will become an even greater contribution
to the repository, since you have added a meaningful test, and
this is always very useful. And finally, with a second pull
request, you already submit changes that fix the code so that it
passes this test. And once again you increase your contribution.
Thus, you have left behind a lot of artifacts in the repository:
an issue, an enhanced test system, and a fixed bug. This will be
an excellent example of implementing the TDD (Test Driven
Development) approach.</p>
<br>
<hr>
<br>
<p>Thus, you and I have gone through the full cycle from the problem to the contribution
to the master branch.:</p>
<pre class="mermaid">
  flowchart LR
    BUG[&#34;Find a bug / feature   &#34;] --&gt; ISSUE[&#34;Create Issue  &#34;]
    ISSUE --&gt; DISCUSS[&#34;Discussion  &#34;]
    DISCUSS --&gt; PR[&#34;Open Pull Request  &#34;]
    PR --&gt; CI[&#34;PR Checks with CI 󰦕 &#34;]
    CI --&gt; REVIEW[&#34;Reviewer Reviews PR  &#34;]
    REVIEW --&gt; MERGE[&#34;Merge PR into main  &#34;]
    MERGE --&gt; BUG
</pre>

<p>You can test your strength right now by finding a suitable issue
using these wonderful services:</p>
<ul>
<li><a href="https://goodfirstissue.dev/">Good First Issue</a> — Issues that
are great for beginners.</li>
<li><a href="https://github.com/MunGell/awesome-for-beginners">Awesome for
Beginners</a>
— A collection of projects for beginners.</li>
<li><a href="https://up-for-grabs.net/#/">Up For Grabs</a> — Tasks open for
solving across various technologies.</li>
<li><a href="https://github.com/firstcontributions/first-contributions">First
Contributions</a>
— A repository with a manual and a list of open projects.</li>
<li><a href="https://www.firsttimersonly.com/">First Timers Only</a> — More
similar resources.</li>
</ul>
<p>Do not forget that you yourself can also register your projects
on these resources to attract new developers!</p>





<blockquote class="markdown-alert markdown-alert--note">
  <div class="markdown-alert__title">
    
      <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"/></svg>
    

    
      GitHub CLI
    
  </div>

  <p>If you are interested in productive work with GitHub from the
console using the <code>gh</code> utility, pay attention to it
<a href="https://cli.github.com/manual/">documentation</a>. And also for
that, that <code>gh</code> supports extensions that you can familiarize
yourself with you can use the <code>gh ext browse</code> command or write
your own!</p>
</blockquote>
<p>Some additional reading:</p>
<ul>
<li><a href="https://opensource.guide/how-to-contribute/">Official GitHub
guideline</a></li>
<li><a href="https://navendu.me/posts/pull-requests-like-a-pro/">Pull Requests like a Pro, Navendu
Pottekkat</a></li>
<li><a href="https://dev.to/helloquash/10-common-mistakes-to-avoid-when-contributing-to-open-source-projects-1mna">10 Common Mistakes to Avoid When Contributing to Open Source
Projects</a></li>
<li><a href="https://github-help-wanted.com/open-source/beginners-guide/">Open Source for
Beginners</a></li>
</ul>
]]></content:encoded><category>open-source</category><category>eosp</category></item><item><title>Probabilistic hypothesis testing</title><link>https://alchemmist.xyz/articles/probabilistic-hypothesis-testing/</link><pubDate>Sat, 13 Dec 2025 14:47:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/probabilistic-hypothesis-testing/</guid><description>We have a coin, with $p - \text{probability of 1 (head)}$ and $(1 - p) - \text{probability of 0 (tail)}$. We tossed it $n$ times and got a results: $n: x_1, x_2, \dots, x_n \in \{0, 1\}$. Our task it will be a checking the truth of hypothesis $H_0: p = 0.5$. If $H_0$ will be false, we need to choose alternative hypothesis $H_1: p \neq 0.5$.
Firstly, let’s make a little speculations, using our intuition. We, sure, if $\sum\limits_{i = 1}^{n}{x_i} = n$, that $H_0$ is false, because we haven’t reason for assume, that coin can be $0$, therefore $p = 1$. But, what about case, when we have $n = 20$ and $\sum{x_i} = 15$? In this case, we can’t be sure. Our questions, it’s, how to make a decision in such situations. In this decision we may make a one of two types of errors:</description><content:encoded><![CDATA[<p>We have a coin, with $p - \text{probability of 1 (head)}$ and $(1 - p) - \text{probability of 0 (tail)}$. We tossed it $n$ times and got a results: $n: x_1, x_2, \dots, x_n \in \{0, 1\}$. Our task it will be a checking the truth of hypothesis $H_0: p = 0.5$. If $H_0$ will be false, we need to choose alternative hypothesis $H_1: p \neq 0.5$.</p>
<p>Firstly, let’s make a little speculations, using our intuition. We, sure, if $\sum\limits_{i = 1}^{n}{x_i} = n$, that $H_0$ is false, because we haven’t reason for assume, that coin can be $0$, therefore $p = 1$. But, what about case, when we have $n = 20$ and $\sum{x_i} = 15$? In this case, we can’t be sure. Our questions, it’s, how to make a decision in such situations. In this decision we may make a one of two types of errors:
</p>
$$
\begin{align*}
&Type \ 1: \text{In actual fact }H_0\text{ is \textbf{true}, but we told is \textbf{false}.}\\
&Type \ 2: \text{In actual fact }H_0\text{ is \textbf{false}, but we told is \textbf{true}.}\\
\end{align*}
$$<p>
And in statistics our default predisposition it’s minimization errors of type 1. For example, if we made a medicine drug and after testing we checking $H_0$: “Our medicine drug is effective.”. If we make error of type 1, we will put broken drug to many peoples — it’s not good. In business, if make first type error we need to spend more many for new model. That’s the reason, for:
</p>
$$
P[Type 1] < \alpha, \quad \alpha \text{ — significance level}
$$<p>
For make this decision we need to compare $\sum{x_i}$ with $0.5n$. How big is difference? The theorem of Moivre–Laplace:
</p>
$$
\frac{\mu - nP}{\sqrt{np\cdot(1 - p)}} \sim \mathcal{N}(0, 1),\qquad \mu = \sum{x_i}
$$<p>
Let’s use it in our case:
</p>
$$
Z = \frac{\mu - 0.5n}{\sqrt{0.25n}} \sim \mathcal{N}(0, 1)
$$<p>
For example, if in real experiment we got $Z = 10$, that’s mean $H_0$ is <strong>very</strong> unlikely. So, we need to define the border $t$ for $Z$, after that we reject $H_0$:
<img
    src="/images/gaus-2_hu_f79d70c0a6f02165.webp"
    width="1600"
    height="512"
    class="content-img" style="width:500px"
    alt=""
    loading="lazy"
    decoding="async"
  />
We need to find the value of $t$, that probability of cross over it, is significance level $\alpha$.  If $|Z| > q_{1 - \frac{\alpha}{2}}$, we talk $H_1$ is truth and we reject $H_0$. Else, we approve $H_0$.</p>
<p>The interesting fact is first type of errors very easy for control. We can always say, that $H_0$ is truth. Then probability of errors type 1 will equal zero.</p>
]]></content:encoded><category>math</category></item><item><title>Note on SQL Basics</title><link>https://alchemmist.xyz/articles/sql-basics-note/</link><pubDate>Sun, 12 Oct 2025 18:55:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/sql-basics-note/</guid><description>This is my simple note about basic data types in SQL and foundation of SQL — relation algebra. Let’s start from little cheat sheet of data types:
Whole numbers:
TINYINT — from $-128$ to $127$. SMALLINT — from $-32 768$ to $32 767$. INTAGER — from $−2 147 483 648$ to $−2 147 483 647$. BIGINT — very big! Float numbers:
FLOAT — single precision, approximately 7-8 significant digits. DOUBLE — double precision, approximately 15-16 significant digits. NUMERIC / DECIMAL — fixed precision, use as NUMERIC(precision, scale), where precision – total digits count, scale – count digits after dot. Strings:</description><content:encoded><![CDATA[<p>This is my simple note about basic data types in SQL and foundation of SQL — relation algebra. Let’s start from little cheat sheet of data types:</p>
<p><strong>Whole numbers:</strong></p>
<ul>
<li><code>TINYINT</code> — from $-128$ to $127$.</li>
<li><code>SMALLINT</code> — from $-32 768$ to $32 767$.</li>
<li><code>INTAGER</code> — from $−2 147 483 648$ to $−2 147 483 647$.</li>
<li><code>BIGINT</code> — very big!</li>
</ul>
<p><strong>Float numbers:</strong></p>
<ul>
<li><code>FLOAT</code> — single precision, approximately 7-8 significant digits.</li>
<li><code>DOUBLE</code> — double precision, approximately 15-16 significant digits.</li>
<li><code>NUMERIC</code> / <code>DECIMAL</code> — fixed precision, use as <code>NUMERIC(precision, scale)</code>, where <code>precision</code> – total digits count, <code>scale</code> – count digits after dot.</li>
</ul>
<p><strong>Strings:</strong></p>
<ul>
<li><code>CHAR(n)</code> — string of fixed length. <code>n</code> defined maximum string length, if string less than <code>n</code> it sill be fill with spaces.</li>
<li><code>VARCHAR(n)</code> — string of variable length. <code>n</code> defined maximum string length. It’s more optimized and effective, because keep only real string length.</li>
<li><code>TEXT</code> — string of variable length, without limits (it depends on DBMS).</li>
<li><code>ENUM</code> — enumerate. Keep only one from defined list values, for example <code>ENUM('male', 'female', 'other')</code>.</li>
</ul>
<p><strong>Date and time:</strong></p>
<ul>
<li><code>DATE</code> — store only date (year, month, day).</li>
<li><code>TIME</code> — store only time (hours, minutes, seconds).</li>
<li><code>DATETIME</code> — store time and date.</li>
<li><code>TIMESTAMP</code> — store date and time, considering time zone.</li>
</ul>
<p><strong>Logical data:</strong></p>
<ul>
<li><code>BOOLEAN</code> — store logical value: <code>TRUE</code> or <code>FALSE</code>. Some time can be represented as <code>TINYINT</code> with $1 = \texttt{TRUE}$ and $2 = \texttt{FALSE}$.</li>
</ul>
<p><strong>Binary data:</strong></p>
<ul>
<li><code>BLOB</code> (<em>Binary Large Object</em>) — store big binary data, like images, videos, audios and so on.</li>
<li><code>BINARY(n)</code> — binary string with fixed length <code>n</code>.</li>
<li><code>VARBINARY(n)</code> — binary string with variable length, but max length is <code>n</code>.</li>
</ul>
<p><strong>Other:</strong></p>
<ul>
<li><code>JSON</code> — store the json data.</li>
<li><code>XML</code> — store xml data.</li>
</ul>

<h2 id="relation-algebra">
  <a class="link" href="#relation-algebra">
    #
  </a>
  Relation algebra
</h2>

<p>Relational algebra serves is the theoretical basis for SQL. This means that any query that can be expressed in SQL can also be expressed in relational algebra, and vice versa. Understanding relational algebra helps you understand how SQL queries are processed and optimized.</p>
<p>Key concepts:</p>
<ul>
<li><strong>Relation</strong> — in relation algebra it’s the similar as table in database: columns and rows.</li>
<li><strong>Attribute</strong> — column in relation.</li>
<li><strong>Tuple</strong> — row in relation.</li>
<li><strong>Relation Schema</strong> — description structure of relation, which include attributes names and data types.</li>
</ul>
<p>Let’s see on operators of relation algebra. You can try all of this examples in <a href="https://dbis-uibk.github.io/relax/calc/local/uibk/local/0">RealX</a>.</p>
<p><strong>π (pi)</strong> — Operation, that create new relation, selecting specified attributes from source relation. It’s similar as <code>SELECT</code> in SQL. For example we can get the list of all books titles and authors:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="err">π</span><span class="w"> </span><span class="n">author</span><span class="p">,</span><span class="w"> </span><span class="n">title</span><span class="w"> </span><span class="p">(</span><span class="n">books</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p>As result:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plaintext" data-lang="plaintext"><span class="line"><span class="cl">+-----------------+-----------------------------+
</span></span><span class="line"><span class="cl">| author          | title                       |
</span></span><span class="line"><span class="cl">|-----------------+-----------------------------|
</span></span><span class="line"><span class="cl">| Salinger        | The catcher in the Rye      |
</span></span><span class="line"><span class="cl">| Robert Martin   | Clean code                  |
</span></span><span class="line"><span class="cl">| Platon          | The State                   |
</span></span><span class="line"><span class="cl">+-----------------+-----------------------------+
</span></span></code></pre></div><p><strong><code>σ</code> (sigma)</strong> — Operation, that create new relation contains only tuples, which satisfy specified condition. It’s similar as <code>WHERE</code> in SQL. This example give me the books only from Salinger:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="err">σ</span><span class="w"> </span><span class="n">author</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&#34;Salinger&#34;</span><span class="w"> </span><span class="p">(</span><span class="n">books</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p><strong><code>∪</code> (union)</strong> — Operation, that create new relation contains all tuples, which exists at least one of two source relations. Its similar as <code>UNION</code> in SQL. I can union books from Salinger and books published at 2024-01-05:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="p">(</span><span class="err">σ</span><span class="w"> </span><span class="n">author</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;Selinger&#39;</span><span class="w"> </span><span class="p">(</span><span class="n">books</span><span class="p">))</span><span class="w"> </span><span class="err">∪</span><span class="w"> </span><span class="p">(</span><span class="err">σ</span><span class="w"> </span><span class="n">publish_at</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;2024-01-05&#39;</span><span class="w"> </span><span class="p">(</span><span class="n">books</span><span class="p">))</span><span class="w">
</span></span></span></code></pre></div><p><strong><code>−</code> (subtraction)</strong> — Operation, that create new relation, includes tuples, which contains into first relation but missing in second. Next example show ids of books, that no from Salinger.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="err">π</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="p">(</span><span class="n">books</span><span class="p">)</span><span class="w"> </span><span class="err">–</span><span class="w"> </span><span class="err">π</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="p">(</span><span class="err">σ</span><span class="w"> </span><span class="n">author</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;Salinger&#39;</span><span class="w"> </span><span class="p">(</span><span class="n">books</span><span class="p">))</span><span class="w">
</span></span></span></code></pre></div><p><strong><code>×</code> (cross join)</strong> — Operation, that create new relation contains all combinations of tuples from two source relations. It’s similar as <code>CROSS JOIN</code> in SQL. For example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="p">(</span><span class="err">σ</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">(</span><span class="n">books</span><span class="p">))</span><span class="w"> </span><span class="err">×</span><span class="w"> </span><span class="p">(</span><span class="err">σ</span><span class="w"> </span><span class="n">book_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">(</span><span class="n">reviews</span><span class="p">))</span><span class="w">
</span></span></span></code></pre></div><p><strong><code>⋈</code> (natural join)</strong> — Operation, that create new relation, contains tuples from two source relations, that have same values in attributes with same name. Duplicated attributes remove from result relation. It’s similar as <code>NATURAL JOIN</code> in SQL. For example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="n">books</span><span class="w"> </span><span class="err">⋈</span><span class="w"> </span><span class="n">reviews</span><span class="w">
</span></span></span></code></pre></div><p><strong><code>⋈ θ</code> (theta join)</strong> — Operation, that create new relation, contains tuples from two source relations and satisfy specified condition <code>θ</code>. Condition can include operators: <code>=</code>, <code>≠</code>, <code>&gt;</code>, <code>&lt;</code>, <code>≥</code>, <code>≤</code>.  For example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="p">(</span><span class="n">books</span><span class="p">)</span><span class="w"> </span><span class="err">⋈</span><span class="w"> </span><span class="n">books</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">reviews</span><span class="p">.</span><span class="n">book_id</span><span class="w"> </span><span class="p">(</span><span class="n">reviews</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p><strong><code>⋈ =</code> (equjoin)</strong> — A special case of theta join, where condition is equal values of attributes. The previous example show this.</p>
<p><strong><code>÷</code> (division)</strong> — Binary operation, that create new relation, contains tuples from first source relation, that connected with all tuples from second source relation. This is a powerful operator for solving tasks like: “Find all X, that connected with Y.” For example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="err">π</span><span class="w"> </span><span class="n">title</span><span class="p">,</span><span class="w"> </span><span class="n">author</span><span class="w"> </span><span class="p">(</span><span class="err">σ</span><span class="w"> </span><span class="n">status</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;available&#39;</span><span class="w"> </span><span class="p">(</span><span class="n">library</span><span class="p">))</span><span class="w"> </span><span class="err">÷</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="err">π</span><span class="w"> </span><span class="n">title</span><span class="w"> </span><span class="p">(</span><span class="err">σ</span><span class="w"> </span><span class="n">author</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;Selinjer&#39;</span><span class="w"> </span><span class="p">(</span><span class="n">books</span><span class="p">))</span><span class="w">
</span></span></span></code></pre></div><p>Here is two terms, first is <code>π title, author (σ status = 'available' (library))</code> and it’s return the available books with <code>title</code> and <code>author</code> attributes:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plaintext" data-lang="plaintext"><span class="line"><span class="cl">+-----------------+-----------------------------+
</span></span><span class="line"><span class="cl">| author          | title                       |
</span></span><span class="line"><span class="cl">|-----------------+-----------------------------|
</span></span><span class="line"><span class="cl">| Salinger        | The catcher in the Rye      |
</span></span><span class="line"><span class="cl">| Robert Martin   | Clean Code                  |
</span></span><span class="line"><span class="cl">| Platon          | The State                   |
</span></span><span class="line"><span class="cl">| Selinjer        | Advanced Algebra            |
</span></span><span class="line"><span class="cl">| Selinjer        | Linear Algebra              |
</span></span><span class="line"><span class="cl">+-----------------+-----------------------------+
</span></span></code></pre></div><p>Second term <code>π title (σ publish_at = '2024-01-05' (books))</code> is return the list of <code>Selinjer</code> books:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plaintext" data-lang="plaintext"><span class="line"><span class="cl">+------------------+
</span></span><span class="line"><span class="cl">| author           |
</span></span><span class="line"><span class="cl">|------------------|
</span></span><span class="line"><span class="cl">| Selinjer         |
</span></span><span class="line"><span class="cl">| Stive Machonnel  |
</span></span><span class="line"><span class="cl">+------------------+
</span></span></code></pre></div><p>Division of this two relations will return the list of titles where authors equals and drop author attribute:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plaintext" data-lang="plaintext"><span class="line"><span class="cl">+-----------------------------+
</span></span><span class="line"><span class="cl">| title                       |
</span></span><span class="line"><span class="cl">|-----------------------------|
</span></span><span class="line"><span class="cl">| Advanced Algebra            |
</span></span><span class="line"><span class="cl">| Linear Algebra              |
</span></span><span class="line"><span class="cl">+-----------------------------+
</span></span></code></pre></div><p>This is the available books in library from author published it at <code>'2024-01-05'</code>.</p>
<p><strong><code>γ</code> (aggregation)</strong> — Operation, that groups tuples by specified attributes and execute aggregate function (<em>sum, max, min, count, average</em>). It’s similar as <code>GROUP BY</code> in SQL. For example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="err">γ</span><span class="w"> </span><span class="n">title</span><span class="p">;</span><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="n">author</span><span class="p">)</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="k">count</span><span class="w"> </span><span class="p">(</span><span class="n">books</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div>]]></content:encoded><category>sql</category></item><item><title>Welford algorithm</title><link>https://alchemmist.xyz/articles/welford-algorithm/</link><pubDate>Wed, 10 Sep 2025 17:31:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/welford-algorithm/</guid><description>Imagine that data is streaming to you: millions of transactions, stock prices, sensor readings. You need to calculate the mean, variance, and correlations. The classic way is to save all the data and then calculate it. But it takes up a lot of memory, calculations are getting heavy, rounding errors occur on large numbers. Recently, I came across to Welford algorithm, which can be online calculating in one iteration without save big data. It’s very elegant, stable and exact algorithm.</description><content:encoded><![CDATA[<p>Imagine that data is streaming to you: millions of transactions, stock prices, sensor readings. You need to calculate the mean, variance, and correlations. The classic way is to save all the data and then calculate it. But it takes up a lot of memory, calculations are getting heavy, rounding errors occur on large numbers. Recently, I came across to Welford algorithm, which can be online calculating in one iteration without save big data. It’s very elegant, stable and exact algorithm.</p>
<p>The problem settings is pretty simple: we want to calculate statistics (mean, variance, covariance, correlation) step by step, when we receive $n$ data in a stream, without saving all data and additional iteration. Let’s remind formulas on base way. Mean:
</p>
$$
\overline{x} = \frac{1}{n}\sum\limits_{i = 1}^{n}x_i
$$<p>
Variance:
</p>
$$
s^2 = \frac{1}{n - 1}\sum\limits_{i = 1}^{n}(x_i - \overline{x})^2
$$<p>
As you see for mean we need sum: first problem — how to get sum without all numbers? And for variance we need mean: second problem — how to know mean without all data?</p>

<h2 id="intuition-of-method">
  <a class="link" href="#intuition-of-method">
    #
  </a>
  Intuition of method
</h2>

<p>Let’s try to feel the intuition of Welford method. Imagine we have the dataset: $A = \{1, 2, 3\}$, mean of this dataset is $\overline{x}_A = \frac{1 + 2 +3}{3} = 2$ and then we got one more number: $6$. Do you feel it will be move our mean to the bigger side? But how much bigger? Imagine similar dataset but with more data: $B = \{1, 1, 2, 2, 3, 3\}$ the mean also is $2$ and we also adding number $6$. Again we fill it will be move to the bigger side, but no so strong. Let’s check our intuition:
</p>
$$
\begin{align*}
&A' = \{1, 2, 3, 6\}, \quad \overline{x}_{A'} = \frac{1 + 2 + 3 + 6}{4} = 3, \quad \Delta_A = |\overline{x}_A - \overline{x}_{A'}| = 1 \\
&B' = \{1, 1, 2, 2, 3, 3, 6\},  \quad \overline{x}_{B'} = \frac{2(1 + 2 + 3) + 6}{7} \approx 2.57, \quad \Delta_{B} = \overline{x}_B - \overline{x}_{B'} \approx 0.57
\end{align*}
$$<p>
Our intuition was right! It remains for us to figure out how we can calculate this delta, if we got only previous mean $\overline{x}_{i - 1}$, new number $x_i$ and count of our numbers. The Welford method told: every new value move mean in its own direction with weight $1/i$:
</p>
$$
\overline{x}_i = \overline{x}_{i - 1} + \frac{1}{i}(x_i - \overline{x}_{i - 1})
$$<p>
Let’s check it for $B$ dataset. We got mean without new number $\overline{x}_{i - 1} = 2$ and new number $x_i = 6$ and it’s a seventh number, $i = 7$. Goal is find a $\overline{x}_i$ mean with Welfod forumula:
</p>
$$
\overline{x}_i = 2 + \frac{1}{7}(6 - 2) = 2 + 0.57\ldotp\!\ldotp\!\ldotp \ \approx 2.57
$$<p>
It’s absolutely exact value, as you see. Nice!</p>

<h2 id="variance-correlation-covariance">
  <a class="link" href="#variance-correlation-covariance">
    #
  </a>
  Variance, correlation, covariance
</h2>

<p>The real power of Welford&rsquo;s algorithm reveals itself when calculating variance. The naive approach requires storing all data points and recalculating the mean before computing variance, which is computationally expensive. Welford&rsquo;s method elegantly solves this by maintaining a running estimate of variance using the following recurrence relation:</p>
<p>For variance, we maintain the current mean $\overline{x}$ and the sum of squares of differences $S$. For each new data point $x_n$ at step $n$:
</p>
$$
\begin{gather*}
\overline{x}_n = \overline{x}_{n-1} + \frac{1}{n}(x_n - \overline{x}_{n-1}) \\
S_n = S_{n-1} + (x_n - \overline{x}_{n-1})(x_n - \overline{x}_n)
\end{gather*}
$$<p>
The population variance can then be calculated as $\sigma^2 = S_n/n$, while the sample variance is $s^2 = S_n/(n-1)$.</p>
<p>This approach extends beautifully to covariance and correlation. For two variables $X$ and $Y$, we maintain counts $n$, means $\overline{x}$ and $\overline{y}$, and accumulated products $C_{xy}$:
</p>
$$
\begin{gather*}
\delta_x = x_n - \overline{x}_{n-1}, \quad
\delta_y = y_n - \overline{y}_{n-1} \\
\overline{x}_n = \overline{x}_{n-1} + \frac{\delta_x}{n}, \quad
\overline{y}_n = \overline{y}_{n-1} + \frac{\delta_y}{n} \\
C_{xy_n} = C_{xy_{n-1}} + \delta_x (y_n - \overline{y}_n) \\
\end{gather*}
$$<p>
The covariance is then $\text{cov}(X,Y) = \frac{C_{xy_n}}{(n-1)}$ and correlation is $\text{corr}(X,Y) = \frac{C_{xy_n}}{\sqrt{S_{x_n} S_{y_n}}}$.</p>

<h2 id="c-implementation">
  <a class="link" href="#c-implementation">
    #
  </a>
  C implementation
</h2>

<p>Here&rsquo;s a complete C implementation of Welford&rsquo;s algorithm for calculating mean and variance:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;math.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">long</span> <span class="kt">long</span> <span class="n">n</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">double</span> <span class="n">mean</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">double</span> <span class="n">M2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="n">welford_state</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">welford_update</span><span class="p">(</span><span class="n">welford_state</span> <span class="o">*</span><span class="n">state</span><span class="p">,</span> <span class="kt">double</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">state</span><span class="o">-&gt;</span><span class="n">n</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">double</span> <span class="n">delta</span> <span class="o">=</span> <span class="n">x</span> <span class="o">-</span> <span class="n">state</span><span class="o">-&gt;</span><span class="n">mean</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">state</span><span class="o">-&gt;</span><span class="n">mean</span> <span class="o">+=</span> <span class="n">delta</span> <span class="o">/</span> <span class="n">state</span><span class="o">-&gt;</span><span class="n">n</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">state</span><span class="o">-&gt;</span><span class="n">M2</span> <span class="o">+=</span> <span class="n">delta</span> <span class="o">*</span> <span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">state</span><span class="o">-&gt;</span><span class="n">mean</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">double</span> <span class="nf">welford_mean</span><span class="p">(</span><span class="k">const</span> <span class="n">welford_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">state</span><span class="o">-&gt;</span><span class="n">mean</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">double</span> <span class="nf">welford_variance</span><span class="p">(</span><span class="k">const</span> <span class="n">welford_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">n</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="o">?</span> <span class="n">state</span><span class="o">-&gt;</span><span class="n">M2</span> <span class="o">/</span> <span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">:</span> <span class="mf">0.0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">double</span> <span class="nf">welford_stddev</span><span class="p">(</span><span class="k">const</span> <span class="n">welford_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nf">sqrt</span><span class="p">(</span><span class="nf">welford_variance</span><span class="p">(</span><span class="n">state</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">welford_state</span> <span class="n">state</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="kt">double</span> <span class="n">test_data</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">,</span> <span class="mf">6.0</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="kt">size_t</span> <span class="n">data_size</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">test_data</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">test_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">data_size</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">welford_update</span><span class="p">(</span><span class="o">&amp;</span><span class="n">state</span><span class="p">,</span> <span class="n">test_data</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;Added %.1f: mean=%.3f, variance=%.3f, stddev=%.3f</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">               <span class="n">test_data</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="nf">welford_mean</span><span class="p">(</span><span class="o">&amp;</span><span class="n">state</span><span class="p">),</span> 
</span></span><span class="line"><span class="cl">               <span class="nf">welford_variance</span><span class="p">(</span><span class="o">&amp;</span><span class="n">state</span><span class="p">),</span> <span class="nf">welford_stddev</span><span class="p">(</span><span class="o">&amp;</span><span class="n">state</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>For covariance and correlation, we can extend this approach:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">long</span> <span class="kt">long</span> <span class="n">n</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">double</span> <span class="n">mean_x</span><span class="p">,</span> <span class="n">mean_y</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">double</span> <span class="n">C2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="n">welford_cov_state</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">welford_cov_update</span><span class="p">(</span><span class="n">welford_cov_state</span> <span class="o">*</span><span class="n">state</span><span class="p">,</span> <span class="kt">double</span> <span class="n">x</span><span class="p">,</span> <span class="kt">double</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">state</span><span class="o">-&gt;</span><span class="n">n</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">double</span> <span class="n">delta_x</span> <span class="o">=</span> <span class="n">x</span> <span class="o">-</span> <span class="n">state</span><span class="o">-&gt;</span><span class="n">mean_x</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">double</span> <span class="n">delta_y</span> <span class="o">=</span> <span class="n">y</span> <span class="o">-</span> <span class="n">state</span><span class="o">-&gt;</span><span class="n">mean_y</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">state</span><span class="o">-&gt;</span><span class="n">mean_x</span> <span class="o">+=</span> <span class="n">delta_x</span> <span class="o">/</span> <span class="n">state</span><span class="o">-&gt;</span><span class="n">n</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">state</span><span class="o">-&gt;</span><span class="n">mean_y</span> <span class="o">+=</span> <span class="n">delta_y</span> <span class="o">/</span> <span class="n">state</span><span class="o">-&gt;</span><span class="n">n</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">state</span><span class="o">-&gt;</span><span class="n">C2</span> <span class="o">+=</span> <span class="n">delta_x</span> <span class="o">*</span> <span class="p">(</span><span class="n">y</span> <span class="o">-</span> <span class="n">state</span><span class="o">-&gt;</span><span class="n">mean_y</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">double</span> <span class="nf">welford_covariance</span><span class="p">(</span><span class="k">const</span> <span class="n">welford_cov_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">n</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="o">?</span> <span class="n">state</span><span class="o">-&gt;</span><span class="n">C2</span> <span class="o">/</span> <span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">:</span> <span class="mf">0.0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div>]]></content:encoded><category>algorithms</category><category>C</category><category>math</category></item><item><title>Devsyringe: Stop Copy-Pasting Dynamic Values</title><link>https://alchemmist.xyz/articles/the-devsyringe/</link><pubDate>Fri, 05 Sep 2025 14:22:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/the-devsyringe/</guid><description>Today I want to tell about Injecting Life into Static Files: Building Dynamic Configs with Devsyringe.
As developers, we live in a world of dynamic values. API tokens, temporary URLs from tunneling services like ngrok or localtunnel, database connection strings, and feature flags are the lifeblood of our modern applications. In compiled languages or Node.js environments, we have a rich ecosystem of tools like dotenv and configuration libraries to manage this dynamism seamlessly. They allow us to externalize configuration, injecting values from environment variables or secret managers at runtime.</description><content:encoded><![CDATA[<p>Today I want to tell about Injecting Life into Static Files: Building Dynamic Configs with <a href="https://devsyringe.alchemmist.xyz">Devsyringe</a>.</p>
<p>As developers, we live in a world of dynamic values. API tokens, temporary URLs from tunneling services like <code>ngrok</code> or <code>localtunnel</code>, database connection strings, and feature flags are the lifeblood of our modern applications. In compiled languages or Node.js environments, we have a rich ecosystem of tools like <code>dotenv</code> and configuration libraries to manage this dynamism seamlessly. They allow us to externalize configuration, injecting values from environment variables or secret managers at runtime.</p>
<p>But what about the static parts of our projects? Consider a simple HTML file that needs to display a temporary public URL, a JavaScript config object for a lightweight script, or a static configuration file for a legacy system. These aren&rsquo;t processed by a bundler or a framework; they are flat files. The traditional solution is manual, error-prone, and frustrating: run a command, watch its output, copy the new value, open a file, find the right line, paste, save, and then repeat for every other file that needs the same value — boredom. This process breaks flow state and is utterly antithetical to the automation we cherish.</p>
<p>I found myself facing this exact problem one too many times. The constant context-switching between my terminal and editor to update URLs was a nagging inefficiency. I knew there had to be a better way — a way to treat these static files as dynamic endpoints for configuration. This frustration was the catalyst for <strong>Devsyringe</strong>, a CLI utility written in Go designed to automate this very workflow.</p>

<h2 id="the-core-idea-declarative-configuration-injection">
  <a class="link" href="#the-core-idea-declarative-configuration-injection">
    #
  </a>
  The Core Idea: Declarative Configuration Injection
</h2>

<p>The motivation behind Devsyringe wasn&rsquo;t to build another templating engine or a complex build system. The goal was simpler and more focused: to create a tool that can run a command, parse its output for a specific value using a regex, and then inject that value into one or more target files. The entire behavior is defined declaratively in a simple YAML configuration file, typically named <code>devsyringe.yaml</code>.</p>
<p>Think of it as a universal adapter between the dynamic output of CLI tools and the static text of your config files. It&rsquo;s purpose-built for scenarios where heavier solutions are overkill or simply don&rsquo;t fit. The real magic is in the hands-off automation; you define the rules once, and from then on, a single command keeps everything in sync. It&rsquo;s the missing glue that makes your entire setup feel truly dynamic.</p>

<h2 id="real-world-use-cases-and-practical-applications">
  <a class="link" href="#real-world-use-cases-and-practical-applications">
    #
  </a>
  Real-World Use Cases and Practical Applications
</h2>

<p>Let&rsquo;s move beyond abstract concepts and look at practical, powerful use cases that save you from tedious manual work. The pattern is universal — any CLI command that outputs a value you need in a file is a perfect candidate for automation.</p>
<p><strong>The Classic Tunnel Automation.</strong>
When developing web applications, you often need to expose your local server to the internet. Tools like <code>localtunnel</code> or <code>serveo</code> generate unique, random URLs that must be configured in both your frontend and backend code. Here&rsquo;s how Devsyringe handles this automatically:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">serums</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">localtunnel</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">source</span><span class="p">:</span><span class="w"> </span><span class="l">lt --port 8080</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">mask</span><span class="p">:</span><span class="w"> </span><span class="l">https://[a-z0-9\-]+\.loca\.lt</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">targets</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">env_file</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">./.env</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">clues</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;API_BASE_URL&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">frontend_config</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">./src/config.js</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">clues</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;API_URL&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;const&#34;</span><span class="p">]</span><span class="w">
</span></span></span></code></pre></div><p>This configuration defines a complete workflow: execute the tunnel command, extract the URL using regex, and inject it into both the <code>.env</code> file and JavaScript configuration. The entire process becomes a single command: <code>dsy inject</code>.</p>
<p><strong>Dynamic Documentation and Résumé Automation.</strong><br>
Here&rsquo;s a more sophisticated use case: keeping technical documentation or LaTeX-generated résumés updated with live statistics. Imagine your résumé.tex file contains a line like: <code>\newcommand{\githubstars}{427}</code></p>
<p>With Devsyringe, you can automatically populate this with your current GitHub statistics:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">serums</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">github_stats</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">source</span><span class="p">:</span><span class="w"> </span><span class="l">curl -s &#34;https://api.github.com/users/yourusername/repos&#34; | jq &#39;reduce .[] as $repo (0; . + $repo.stargazers_count)&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">mask</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;(\d+)&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">targets</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">resume</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">./resume.tex</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">clues</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;githubstars&#34;</span><span class="p">]</span><span class="w">
</span></span></span></code></pre></div><p>This setup calls the GitHub API, calculates your total star count across all repositories, and updates the LaTeX source file. Your résumé maintains accurate, current statistics without manual intervention — perfect for job applications or portfolio updates. But then you can set up CI for regular updates with each push if you use the resume repository.</p>
<p><strong>Advanced Infrastructure Management.</strong>
For more complex setups, Devsyringe shines in infrastructure automation. Consider these scenarios:</p>
<ul>
<li>Fetching fresh database credentials from HashiCorv Vault and injecting them into application properties</li>
<li>Retrieving current deployment endpoints from service discovery and updating API gateway configurations</li>
<li>Pulling infrastructure IP addresses from cloud providers and updating security group rules</li>
<li>Extracting build metadata from CI systems and updating deployment manifests</li>
</ul>
<p>The pattern remains consistent: command  output extraction  file injection. This simplicity makes it adaptable to countless automation scenarios. If you want a plain value from your hands — no problem, use: <code>echo '&lt;my-value&gt;'</code> as command, devsyringe will do the rest himself.</p>

<h2 id="technical-architecture-and-implementation">
  <a class="link" href="#technical-architecture-and-implementation">
    #
  </a>
  Technical Architecture and Implementation
</h2>

<p>While Devsyringe&rsquo;s concept is simple, building a robust CLI tool requires careful architecture. The project leverages Go&rsquo;s strengths for concurrent processing and cross-platform compatibility while maintaining simplicity and reliability.</p>
<p><strong>Project Structure and Design Patterns.</strong>
The architectural elegance of Devsyringe lies in its deliberate use of the <strong>Decorator Pattern</strong>, which mirrors the layered structure of a cabbage — each leaf wraps around the core, adding functionality while preserving the integrity of the inner layers. This pattern is foundational to the tool’s design: lower-level components remain blissfully unaware of the layers above them, ensuring modularity and separation of concerns.</p>
<p>Crucially, this philosophy extends beyond the tool’s internal architecture to its interaction with your projects. Devsyringe operates as an <strong>invisible decorator</strong> for your codebase. Your application remains completely unaware of its presence—no special imports, hooks, or changes to your code are required. It simply updates static files on disk, and your project runs exactly as it did before, just with new values in place. It’s automation that feels like magic because it leaves no trace of itself behind.</p>
<p>This approach enables seamless integration into any workflow. Whether you’re using it locally to manage tunnel URLs or in CI/CD to inject build-time secrets, Devsyringe enhances your environment without altering its fundamental behavior. Your configuration files remain valid, your build processes unchanged, and your mental model intact — all while gaining the power of dynamic value injection.</p>
<p>The codebase follows standard Go conventions with clear separation of concerns:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plaintext" data-lang="plaintext"><span class="line"><span class="cl">│── cmd
</span></span><span class="line"><span class="cl">│   └── dsy
</span></span><span class="line"><span class="cl">│       └── main.go
</span></span><span class="line"><span class="cl">└── internal
</span></span><span class="line"><span class="cl">    ├── cli
</span></span><span class="line"><span class="cl">    │   ├── commands.go
</span></span><span class="line"><span class="cl">    │   └── tui
</span></span><span class="line"><span class="cl">    │       └── tui.go
</span></span><span class="line"><span class="cl">    ├── config
</span></span><span class="line"><span class="cl">    │   └── config.go
</span></span><span class="line"><span class="cl">    ├── process
</span></span><span class="line"><span class="cl">    │   ├── process.go
</span></span><span class="line"><span class="cl">    │   └── procmanager.go
</span></span><span class="line"><span class="cl">    └── utils
</span></span><span class="line"><span class="cl">        └── utils.go
</span></span></code></pre></div><p>This organization makes the codebase maintainable and testable while keeping logical components separated.</p>
<p><strong>Key Technical Decisions.</strong>
The implementation makes several thoughtful choices that enhance reliability and user experience:</p>
<p>Cobra CLI Framework provides professional-grade command structure, automatic help generation, and shell completion. The TUI interface, built with tview, offers real-time process monitoring that surpasses typical CLI tools:
<img src="/images/demo-devsyringe.gif" class="content-img" style="width:700px" alt="" loading="lazy" decoding="async" />
The process management system uses goroutines and channels for concurrent command execution and output capture. File injection employs simple pattern matching rather than complex parsing, making it universally applicable to any text format.</p>
<p><strong>Robust Error Handling and Validation.</strong>
The tool includes comprehensive error checking at every stage: configuration validation, command execution, output parsing, and file operations. Meaningful error messages guide users toward resolving issues rather than failing cryptically.</p>

<h2 id="distribution-and-cross-platform-compatibility">
  <a class="link" href="#distribution-and-cross-platform-compatibility">
    #
  </a>
  Distribution and Cross-Platform Compatibility
</h2>

<p>A tool is only useful if it&rsquo;s easily installable. Devsyringe leverages modern Go tooling to provide seamless installation across all major platforms.</p>
<p><strong>Automated Builds with Goreleaser.</strong>
The project uses Goreleaser to automate the release process, generating: Cross-platform binaries for Windows, macOS, and Linux, Package manager support (Homebrew, AUR), Debian and RPM packages in <a href="https://github.com/alchemmist/devsyringe/releases">GitHub releases</a> with checksums and signatures. Windows support already in <a href="https://github.com/alchemmist/devsyringe/issues/10">backlog</a>.</p>
<p><strong>Installation Simplicity.</strong>  Users can install through multiple channels. For Go developers:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">go install github.com/alchemmist/devsyringe/cmd/dsy@latest
</span></span></code></pre></div><p>For macOS users:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">brew install devsyringe
</span></span></code></pre></div><p>For Arch Linux users:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">paru -S devsyringe
</span></span></code></pre></div><p>This multi-channel approach ensures the tool is accessible to developers regardless of their preferred environment.</p>

<h2 id="why-devsyringe-will-change-your-workflow">
  <a class="link" href="#why-devsyringe-will-change-your-workflow">
    #
  </a>
  Why Devsyringe Will Change Your Workflow
</h2>

<p>The true value of Devsyringe emerges after the first time you use it in anger. That moment when you realize you&rsquo;ll never again manually update a tunnel URL across multiple files. When your documentation automatically stays current with your API versions. When your résumé updates itself with your latest achievements.</p>
<p>It&rsquo;s not just about time saved — though that accumulates surprisingly fast. It&rsquo;s about maintaining flow state. It&rsquo;s about eliminating the tiny frustrations that add up throughout a development session. It&rsquo;s about having a tool that makes your entire development environment feel more integrated and automated.</p>
<p>The learning curve is intentionally shallow. The YAML configuration is straightforward, the commands are intuitive, and the feedback is immediate. You can go from installation to solving real problems in under five minutes.</p>

<h2 id="getting-started-and-next-steps">
  <a class="link" href="#getting-started-and-next-steps">
    #
  </a>
  Getting Started and Next Steps
</h2>

<p>Ready to eliminate manual file updates from your workflow? Installation is simple:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">go install github.com/alchemmist/devsyringe/cmd/dsy@latest
</span></span></code></pre></div><p>Visit the GitHub <a href="https://github.com/alchemmist/devsyringe">repository</a> for complete documentation, examples, and source code. The <code>README</code> contains practical examples you can adapt immediately for your use cases.</p>
<p>Consider where in your workflow you&rsquo;re still copying values between terminal and editor. That&rsquo;s your starting point. Whether it&rsquo;s tunnel URLs, API keys, version numbers, or statistics — Devsyringe can probably automate it. In repository you can find many issues, if you interested of this project, <a href="https://github.com/alchemmist/devsyringe/issues">welcome</a>!</p>
]]></content:encoded><category>tools</category></item><item><title>Privacy screen share in Hyprland</title><link>https://alchemmist.xyz/articles/hyrpland-noscreenshare/</link><pubDate>Sat, 23 Aug 2025 17:14:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/hyrpland-noscreenshare/</guid><description>We’ve all been in a situation when you need to share your screen with many windows, and you need a few minutes before clicking on “Share screen” button, in order to decide. It’s okay, especially if your system is your second (or even first) home: with private notes, documents, passwords, chats and so on.
Next we will set up a useful workflow for this case. But, this setup will use new feature, which is hardwired into Hyprland and most likely absent in other DEs/compositors. I will demonstrate our final goal. For example, my screen share can be looks, like this:</description><content:encoded><![CDATA[<p>We’ve all been in a situation when you need to share your screen with many windows, and you need a few minutes before clicking on “Share screen” button, in order to decide. It’s okay, especially if your system is your second (or even first) home: with private notes, documents, passwords, chats and so on.</p>
<p>Next we will set up a useful workflow for this case. But, this setup will use new feature, which is hardwired into Hyprland and most likely absent in other DEs/compositors. I will demonstrate our final goal. For example, my screen share can be looks, like this:
<img src="/images/noscreenshare-demo.mp4" class="content-img" style="width:85px" alt="" loading="lazy" decoding="async" /></p>
<blockquote class="markdown-blockquote">
  <p>If you like my wallpaper you can find <a href="https://github.com/alchemmist/dotfiles/blob/main/wallpapers/miyazaki/images/1198594-3200x1680-desktop-hd-studio-ghibli-background.jpg">this</a> and more very good stuff in my <code>dotfiles</code> repository on <a href="https://github.com/alchemmist/dotfiles/tree/main/wallpapers">GitHub</a>. Don’f forget: I love your stars!</p>

</blockquote>
<p>Let’s go step-by-step. Firstly, let’s recall that in Hyprland <a href="https://hypr.land/news/update50/#:~:text=on%20by%20default.-,No%20screen%20share,-There%E2%80%99s%20a%20new">release</a> of version <code>0.50.0</code> a new <code>windowrulev2</code> option <code>noscreenshare</code> was added. It’s a new release and now it isn’t controlled from <code>hyprctl</code> only from the config file, like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-plaintext" data-lang="plaintext"><span class="line"><span class="cl">windowrulev2 = noscreenshare, class:^(org.telegram.desktop|obsidian|discord)$
</span></span></code></pre></div><p>This option will tell Hyprland to draw a black rectangle instead of window content (<em>even if this window isn’t in focus or int the background</em>). This works perfect and protects our privacy. But, I’ve found two inconvenient cases: <strong>1.</strong> When we want to make screenshot (<em>in my case, with flameshot</em>) Hyprland interpret it as try to share our screen and hide all privacy windows. <strong>2.</strong> Sometimes, I want to share something from my Obsidian, for example, and dive into configs in this moment — not so good.</p>

<h2 id="cli-control-noscreenshare-option">
  <a class="link" href="#cli-control-noscreenshare-option">
    #
  </a>
  CLI control noscreenshare option
</h2>

<p>To fix this experience, let’s write a script for control window rule in config. If you don’t have time, the full version of the script <a href="https://github.com/alchemmist/dotfiles/blob/main/scripts/toggle_noscreenshare.sh">here</a>. Script will comment or uncomment line in config file with rule and save info about current rule state in maker-file <code>~/.config/hypr/.screenshare_rule_disabled</code>. And script can be run with command <code>toggle</code> to change state to the opposite:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CONFIG_FILE</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$HOME</span><span class="s2">/.config/hypr/hyprland.conf&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">STATE_FILE</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$HOME</span><span class="s2">/.config/hypr/.screenshare_rule_disabled&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">toggle_rule<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">	<span class="c1"># TODO</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">case</span> <span class="si">${</span><span class="nv">1</span><span class="si">}</span> in
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;toggle&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">        toggle_rule
</span></span><span class="line"><span class="cl">        <span class="p">;;</span>
</span></span><span class="line"><span class="cl"><span class="k">esac</span>
</span></span></code></pre></div><p>Let’s write <code>toggle_rule</code> function. We will use <code>sed</code> (<em>Stream Editor</em>) Linux util. It’s one of the most powerful tools for text processing in Linux and Unix systems. It&rsquo;s commonly used for tasks like search and replace, text transformation, and stream editing. Syntax of <code>sed</code>, in general, looks like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">sed <span class="o">[</span>options<span class="o">]</span> <span class="s2">&#34;script&#34;</span> <span class="o">[</span>file...<span class="o">]</span>
</span></span></code></pre></div><p>We need <code>-i</code> option edit file in-place. Then write a script. Firstly we need to find string with <code>noscreenshare</code> rule, like in regex:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="s2">&#34;/windowrolev2.*noscreenshare.*&#34;</span>
</span></span></code></pre></div><p>We start with <code>&quot;/&quot;</code> for write search query, this we need to line start with <code>&quot;windowrolev2&quot;</code>, after that <code>&quot;.*&quot;</code> for any count of any symbols, between which <code>&quot;noscreenshare&quot;</code>. Then we use <code>&quot;/&quot;</code> for end search query, and <code>&quot;s/&quot;</code> (<em>substitute</em>) for replace:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="s2">&#34;/windowrulev2.*noscreenshare.*/s/^#//&#34;</span>
</span></span></code></pre></div><p>Finally, we use <code>&quot;^#&quot;</code> regular expression for find hash at the start of line and replace it to nothing: <code>&quot;//&quot;</code>. Full command looks like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">sed -i <span class="s1">&#39;/windowrulev2.*noscreenshare.*/s/^#//&#39;</span> <span class="s2">&#34;</span><span class="nv">$CONFIG_FILE</span><span class="s2">&#34;</span>
</span></span></code></pre></div><p>Then use <code>sed</code> for add hash to start of line similar, depending on existence of marker-file:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">toggle_rule<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="o">[</span> -f <span class="s2">&#34;</span><span class="nv">$STATE_FILE</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        sed -i <span class="s1">&#39;/windowrulev2.*noscreenshare.*/s/^#//&#39;</span> <span class="s2">&#34;</span><span class="nv">$CONFIG_FILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        rm -f <span class="s2">&#34;</span><span class="nv">$STATE_FILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">CLASS</span><span class="o">=</span><span class="s2">&#34;on&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">        sed -i <span class="s1">&#39;/windowrulev2.*noscreenshare.*/s/^/#/&#39;</span> <span class="s2">&#34;</span><span class="nv">$CONFIG_FILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        touch <span class="s2">&#34;</span><span class="nv">$STATE_FILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">CLASS</span><span class="o">=</span><span class="s2">&#34;of&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span></code></pre></div><p>In last step of script, we call this function, if <code>toggle</code> option was given, and return a json-like string for waybar. Full script:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CONFIG_FILE</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$HOME</span><span class="s2">/.config/hypr/hyprland.conf&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">STATE_FILE</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$HOME</span><span class="s2">/.config/hypr/.screenshare_rule_disabled&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">toggle_rule<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="o">[</span> -f <span class="s2">&#34;</span><span class="nv">$STATE_FILE</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        sed -i <span class="s1">&#39;/windowrulev2.*noscreenshare.*/s/^#//&#39;</span> <span class="s2">&#34;</span><span class="nv">$CONFIG_FILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        rm -f <span class="s2">&#34;</span><span class="nv">$STATE_FILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">CLASS</span><span class="o">=</span><span class="s2">&#34;on&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">        sed -i <span class="s1">&#39;/windowrulev2.*noscreenshare.*/s/^/#/&#39;</span> <span class="s2">&#34;</span><span class="nv">$CONFIG_FILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        touch <span class="s2">&#34;</span><span class="nv">$STATE_FILE</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">CLASS</span><span class="o">=</span><span class="s2">&#34;off&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">case</span> <span class="si">${</span><span class="nv">1</span><span class="si">}</span> in
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;toggle&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">        toggle_rule
</span></span><span class="line"><span class="cl">        <span class="p">;;</span>
</span></span><span class="line"><span class="cl">    *<span class="o">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="o">[</span> -f <span class="s2">&#34;</span><span class="nv">$STATE_FILE</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">            <span class="nv">CLASS</span><span class="o">=</span><span class="s2">&#34;off&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span>
</span></span><span class="line"><span class="cl">            <span class="nv">CLASS</span><span class="o">=</span><span class="s2">&#34;on&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">fi</span>
</span></span><span class="line"><span class="cl">        <span class="p">;;</span>
</span></span><span class="line"><span class="cl"><span class="k">esac</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;{\&#34;class\&#34;: \&#34;</span><span class="nv">$CLASS</span><span class="s2">\&#34;, \&#34;alt\&#34;: \&#34;</span><span class="nv">$CLASS</span><span class="s2">\&#34;}&#34;</span>
</span></span></code></pre></div>
<h2 id="waybar-module">
  <a class="link" href="#waybar-module">
    #
  </a>
  Waybar module
</h2>

<p>To use this conveniently and instantly detect the current privacy state we write a waybar module:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">&#34;custom/noscreenshare&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;exec&#34;</span><span class="p">:</span> <span class="s2">&#34;~/scripts/toggle_noscreenshare.sh&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;on-click&#34;</span><span class="p">:</span> <span class="s2">&#34;~/scripts/toggle_noscreenshare.sh toggle &amp;&amp; pkill -SIGRTMIN+4 waybar&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;signal&#34;</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;interval&#34;</span><span class="p">:</span> <span class="s2">&#34;once&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;return-type&#34;</span><span class="p">:</span> <span class="s2">&#34;json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;format&#34;</span><span class="p">:</span> <span class="s2">&#34;{icon}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;format-icons&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;off&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;on&#34;</span><span class="p">:</span> <span class="s2">&#34;󰗹&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;tooltip&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="err">,</span>
</span></span></code></pre></div><p>Let’s describe whats going on here. To get value for this module we use <code>exec</code> field and set our script. Then we defined what will happen, when we click on module at <code>on-click</code> option: run script with <code>toggle</code> option and send system signal to waybar. This allows you to not reload all waybar process, but only this module. Here it’s very important to sync <code>signal</code> value and number at <code>pkill -SIGRTMIN+4 waybar</code> command, and to make this value unique only for this waybar module. Then we configure to run our script once on waybar startup and define view format (<code>tooltip: false</code> for not showing text, when hovering over cursor) . I’m using this nerdfonts icons for this, but they are not the same size. Therefore I fine-tune padding and add some styles:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">#</span><span class="nn">custom-noscreenshare</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background</span><span class="p">:</span> <span class="mh">#1e1e2e</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">opacity</span><span class="p">:</span> <span class="mf">0.7</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span> <span class="mi">5</span><span class="kt">px</span> <span class="mi">3</span><span class="kt">px</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span> <span class="kc">solid</span> <span class="mh">#181825</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-radius</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">#</span><span class="nn">custom-noscreenshare</span><span class="p">.</span><span class="nc">on</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-size</span><span class="p">:</span> <span class="mi">18</span><span class="kt">px</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl">  <span class="k">padding-right</span><span class="p">:</span> <span class="mi">14</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">#</span><span class="nn">custom-noscreenshare</span><span class="p">.</span><span class="nc">off</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-size</span><span class="p">:</span> <span class="mi">16</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding-right</span><span class="p">:</span> <span class="mi">16</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding-left</span><span class="p">:</span> <span class="mi">9</span><span class="kt">px</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>After that we have got nice interface for hands-on control of our privacy:
<img src="/images/noscreenshare-demo.gif" class="content-img" style="width:700px" alt="" loading="lazy" decoding="async" /></p>
]]></content:encoded><category>linux</category></item><item><title>Predicate Pattern in Go</title><link>https://alchemmist.xyz/articles/predicate-pattern-go/</link><pubDate>Tue, 29 Jul 2025 12:09:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/predicate-pattern-go/</guid><description>If you think this code is idiomatic, elegant and beautiful, read this article!
FindProcess(ByTitle(title)) FindProcess(ByPID(pid)) This code is an example of the result of the predicate pattern. This example is synthetic, but here we’re trying to achieve a similar result here. Firstly, let’s figure out the predicate. Predicate is a function, that returns a boolean value — very simple!
Now, for example, we will write a method findProcess for ProcManager on Go with predicate pattern. The ProcManager has a field processes []*Process, which is slice of processes. And the Process has many unique fields, that we can use to searching. Our method will take a predicate and apply it to all items in the list until the predicate returns true, or the list ends and the search returns hmm... nothing was found.</description><content:encoded><![CDATA[<p>If you think this code is idiomatic, elegant and beautiful, read this article!</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nf">FindProcess</span><span class="p">(</span><span class="nf">ByTitle</span><span class="p">(</span><span class="nx">title</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nf">FindProcess</span><span class="p">(</span><span class="nf">ByPID</span><span class="p">(</span><span class="nx">pid</span><span class="p">))</span><span class="w">
</span></span></span></code></pre></div><p>This code is an example of the result of the predicate pattern. This example is synthetic, but here we’re trying to achieve a similar result here. Firstly, let’s figure out the predicate. <strong>Predicate</strong> is a function, that returns a boolean value — very simple!</p>
<p>Now, for example, we will write a method <code>findProcess</code> for <code>ProcManager</code> on Go with predicate pattern. The <code>ProcManager</code> has a field <code>processes []*Process</code>, which is slice of processes. And the <code>Process</code> has many unique fields, that we can use to searching. Our method will take a <strong>predicate</strong> and apply it to all items in the list until the predicate returns <code>true</code>, or the list ends and the search returns <code>hmm... nothing was found</code>.</p>
<p>For example, in Python we have a standard function <code>filter</code>, which takes an array of items and a predicate function, like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nb">filter</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">],</span> <span class="k">lambda</span> <span class="n">n</span><span class="p">:</span> <span class="n">n</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
</span></span></code></pre></div><p>But here we need to handle predicates manually, because this is a more general function. For our case we add intermediate step: a predicate builder. Finally we will get this scheme:
<img src="/images/predicate-pattern-schema.svg" class="content-img" style="width:900px" alt="" loading="lazy" decoding="async" />
Let’s write a method <code>findProcess</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">pm</span><span class="w"> </span><span class="o">*</span><span class="nx">ProcManager</span><span class="p">)</span><span class="w"> </span><span class="nf">findProcess</span><span class="p">(</span><span class="nx">searchPredicate</span><span class="w"> </span><span class="nx">ProcessSearchPredicate</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="nx">Process</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">pm</span><span class="p">.</span><span class="nx">mu</span><span class="p">.</span><span class="nf">RLock</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">defer</span><span class="w"> </span><span class="nx">pm</span><span class="p">.</span><span class="nx">mu</span><span class="p">.</span><span class="nf">RUnlock</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">proc</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">pm</span><span class="p">.</span><span class="nx">processes</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">if</span><span class="w"> </span><span class="nf">searchPredicate</span><span class="p">(</span><span class="nx">proc</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">			</span><span class="k">return</span><span class="w"> </span><span class="nx">proc</span><span class="p">,</span><span class="w"> </span><span class="kc">nil</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="p">,</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">&#34;no process with this parameter&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>This method takes one argument: <code>searchPredicate</code> with specific type <code>ProcessSearchPreciate</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nx">ProcessSearchPredicate</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">p</span><span class="w"> </span><span class="o">*</span><span class="nx">Process</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w">
</span></span></span></code></pre></div><p>Let’s see: it’s function from <code>Process</code> to <code>bool</code> — a predicate. Then we can write a predicate builder functions, like filter options:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">ByTitle</span><span class="p">(</span><span class="nx">title</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="nx">ProcessSearchPredicate</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">p</span><span class="w"> </span><span class="o">*</span><span class="nx">Process</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">return</span><span class="w"> </span><span class="nx">p</span><span class="p">.</span><span class="nx">Title</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">title</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">ByPID</span><span class="p">(</span><span class="nx">pid</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="nx">ProcessSearchPredicate</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">p</span><span class="w"> </span><span class="o">*</span><span class="nx">Process</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">return</span><span class="w"> </span><span class="nx">p</span><span class="p">.</span><span class="nx">PID</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">pid</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>It will work like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">proc</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">pm</span><span class="p">.</span><span class="nf">findProcess</span><span class="p">(</span><span class="nf">ByTitle</span><span class="p">(</span><span class="nx">title</span><span class="p">))</span><span class="w">
</span></span></span></code></pre></div><p>This is already good, but I want to use autocomplete in my code editor for filter options. To make it we can rewrite filter options from <em>functions</em> to <em>methods</em> and use one empty object to call it, like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nx">ProcessSearchFilter</span><span class="w"> </span><span class="kd">struct</span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">var</span><span class="w"> </span><span class="nx">filter</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">ProcessSearchFilter</span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">f</span><span class="w"> </span><span class="nx">ProcessSearchFilter</span><span class="p">)</span><span class="w"> </span><span class="nf">ByTitle</span><span class="p">(</span><span class="nx">title</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="nx">ProcessSearchPredicate</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">p</span><span class="w"> </span><span class="o">*</span><span class="nx">Process</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">return</span><span class="w"> </span><span class="nx">p</span><span class="p">.</span><span class="nx">Title</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">title</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">f</span><span class="w"> </span><span class="nx">ProcessSearchFilter</span><span class="p">)</span><span class="w"> </span><span class="nf">ByPID</span><span class="p">(</span><span class="nx">pid</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="nx">ProcessSearchPredicate</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">p</span><span class="w"> </span><span class="o">*</span><span class="nx">Process</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">return</span><span class="w"> </span><span class="nx">p</span><span class="p">.</span><span class="nx">PID</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">pid</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>After that we can use like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">proc</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">pm</span><span class="p">.</span><span class="nf">findProcess</span><span class="p">(</span><span class="nx">filter</span><span class="p">.</span><span class="nf">ByTitle</span><span class="p">(</span><span class="nx">title</span><span class="p">))</span><span class="w">
</span></span></span></code></pre></div><p>And my workflow in my code editor is very comfortable:
<img src="/images/predicate-pattern-demo.gif" class="content-img" alt="" loading="lazy" decoding="async" /></p>
<blockquote class="markdown-blockquote">
  <p>If you like my code editor view you can use my Neovim theme: <a href="https://github.com/alchemmist/nothing.nvim">nothing</a>. And you can use my nvim config, find it in my <a href="https://github.com/alchemmist/dotfiles">dotfiles</a></p>

</blockquote>
]]></content:encoded><category>Go</category></item><item><title>Battery degradation on Linux</title><link>https://alchemmist.xyz/articles/battery-degradation/</link><pubDate>Fri, 11 Jul 2025 09:58:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/battery-degradation/</guid><description>We all know our battery not forever. It’s okay, we can replace degraded battery at service and use machine again. But very useful see current state of your battery. In MacOS it’s default feature, on Linux we, of course, can do same thing. Let’s see!
Now we will understand how to find the desired value and then make a beautiful minimalistic waybar module for battery.
# Find a battery degradation value Firstly get list of all power devices:</description><content:encoded><![CDATA[<p>We all know our battery not forever. It’s okay, we can replace degraded battery at service and use machine again. But very useful see current state of your battery. In MacOS it’s default feature, on Linux we, of course, can do same thing. Let’s see!</p>
<p>Now we will understand how to find the desired value and then make a beautiful minimalistic waybar module for battery.</p>

<h2 id="find-a-battery-degradation-value">
  <a class="link" href="#find-a-battery-degradation-value">
    #
  </a>
  Find a battery degradation value
</h2>

<p>Firstly get list of all power devices:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">upower -e
</span></span></code></pre></div><p>Then find battery from this list:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">upower -e <span class="p">|</span> grep BAT
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># For example:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># /org/freedesktop/UPower/devices/battery_BATT</span>
</span></span></code></pre></div><p>Then get detailed information about this device, with <code>-i</code> flag of <code>upower</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">upower -i <span class="k">$(</span>upower -e <span class="p">|</span> grep BAT<span class="k">)</span>
</span></span></code></pre></div><p>We got something like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">  native-path:          BATT
</span></span><span class="line"><span class="cl">  vendor:               DESAY
</span></span><span class="line"><span class="cl">  model:                BASE-BAT
</span></span><span class="line"><span class="cl">  serial:               1
</span></span><span class="line"><span class="cl">  power supply:         yes
</span></span><span class="line"><span class="cl">  updated:              Fri Jul 11 11:37:00 2025 (7 seconds ago)
</span></span><span class="line"><span class="cl">  has history:          yes
</span></span><span class="line"><span class="cl">  has statistics:       yes
</span></span><span class="line"><span class="cl">  battery
</span></span><span class="line"><span class="cl">    present:             yes
</span></span><span class="line"><span class="cl">    rechargeable:        yes
</span></span><span class="line"><span class="cl">    state:               charging
</span></span><span class="line"><span class="cl">    warning-level:       none
</span></span><span class="line"><span class="cl">    energy:              25.514 Wh
</span></span><span class="line"><span class="cl">    energy-empty:        0 Wh
</span></span><span class="line"><span class="cl">    energy-full:         47.5052 Wh
</span></span><span class="line"><span class="cl">    energy-full-design:  59.4247 Wh
</span></span><span class="line"><span class="cl">    energy-rate:         11.1573 W
</span></span><span class="line"><span class="cl">    voltage:             11.972 V
</span></span><span class="line"><span class="cl">    charge-cycles:       650
</span></span><span class="line"><span class="cl">    time to full:        2.0 hours
</span></span><span class="line"><span class="cl">    percentage:          53%
</span></span><span class="line"><span class="cl">    capacity:            79.9417%
</span></span><span class="line"><span class="cl">    technology:          lithium-ion
</span></span><span class="line"><span class="cl">    charge-start-threshold:        75%
</span></span><span class="line"><span class="cl">    charge-end-threshold:          80%
</span></span><span class="line"><span class="cl">    charge-threshold-supported:    yes
</span></span><span class="line"><span class="cl">    icon-name:          &#39;battery-good-charging-symbolic&#39;
</span></span><span class="line"><span class="cl">  History (charge):
</span></span><span class="line"><span class="cl">    1752222927	53.000	charging
</span></span><span class="line"><span class="cl">  History (rate):
</span></span><span class="line"><span class="cl">    1752223020	11.157	charging
</span></span><span class="line"><span class="cl">    1752222990	11.123	charging
</span></span><span class="line"><span class="cl">    1752222987	11.192	charging
</span></span><span class="line"><span class="cl">    1752222957	10.822	charging
</span></span><span class="line"><span class="cl">    1752222927	10.857	charging
</span></span></code></pre></div><p>Here many interesting information, for example charge-cycles, time to full battery, and so on. But now we use two parameters:</p>
<ul>
<li><code>energy-full-design</code> — the original full battery volume</li>
<li><code>energy-full</code> — current battery volume
Deference between this two parameters is degradation of battery:

$$
\text{Degradation} = \left(1 - \frac{E_{\text{full}}}{E_{\text{design}}}\right) \times 100\%
$$
Now let’s calculate this metric in percents.</li>
</ul>
<p>First find this parameters in big output and devide them, with <code>awk</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">upower -i <span class="k">$(</span>upower -e <span class="p">|</span> grep BAT<span class="k">)</span> <span class="p">|</span> awk <span class="s1">&#39;\
</span></span></span><span class="line"><span class="cl"><span class="s1">	/energy-full:/ {ef=$2}\
</span></span></span><span class="line"><span class="cl"><span class="s1">	/energy-full-design:/ {efd=$2}\
</span></span></span><span class="line"><span class="cl"><span class="s1">	END {print ef/efd}&#39;</span>
</span></span></code></pre></div><p>Here we find <code>energy-full</code> and save to variable <code>ef</code>, find <code>enengry-full-design</code> and save to <code>efd</code> variable. On the end we divide them: <code>ef/efd</code>.</p>
<p>After that calculate percent value, with <code>bc</code> <em>(is shell calculator for expression with float numbers)</em>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;(1 - </span><span class="k">$(</span>upower -i <span class="k">$(</span>upower -e <span class="p">|</span> grep BAT<span class="k">)</span> <span class="p">|</span> awk <span class="s1">&#39;\
</span></span></span><span class="line"><span class="cl"><span class="s1">        /energy-full:/ {ef=$2}\
</span></span></span><span class="line"><span class="cl"><span class="s1">        /energy-full-design:/ {efd=$2}\
</span></span></span><span class="line"><span class="cl"><span class="s1">        END {print ef/efd}&#39;</span><span class="k">)</span><span class="s2">) * 100 + 0.5&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">	<span class="p">|</span> bc
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Output example:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 20.558200</span>
</span></span></code></pre></div><p>Here we make <code>+ 0.5</code> for rounding when the fractional part is cut off later.</p>
<p>In last step we need to round value. We make it simple: we already add <code>0.5</code> to value and now it remains to cut off the fractional part with <code>cut</code> util:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;(1 - </span><span class="k">$(</span>upower -i <span class="k">$(</span>upower -e <span class="p">|</span> grep BAT<span class="k">)</span> <span class="p">|</span> awk <span class="s1">&#39;\
</span></span></span><span class="line"><span class="cl"><span class="s1">        /energy-full:/ {ef=$2}\
</span></span></span><span class="line"><span class="cl"><span class="s1">        /energy-full-design:/ {efd=$2}\
</span></span></span><span class="line"><span class="cl"><span class="s1">        END {print ef/efd}&#39;</span><span class="k">)</span><span class="s2">) * 100 + 0.5&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">	<span class="p">|</span> bc <span class="se">\
</span></span></span><span class="line"><span class="cl">	<span class="p">|</span> cut -d<span class="s1">&#39;.&#39;</span> -f1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Output example:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 20</span>
</span></span></code></pre></div><p>Here <code>-d'.'</code> means we split by dot and <code>-f1</code> means we take first part.</p>

<h2 id="waybar-module">
  <a class="link" href="#waybar-module">
    #
  </a>
  Waybar module
</h2>

<p>In my waybar config <code>~/.config/waybar/config.json</code> I’m add two modules on right section, but you can do as you want. Finally i’m got this:
<img
    src="/images/battery-waybar-module_hu_7adf571591eb9de4.webp"
    width="1600"
    height="1050"
    class="content-img"
    alt=""
    loading="lazy"
    decoding="async"
  /></p>
<blockquote class="markdown-blockquote">
  <p>If you like my wallpaper you can find <a href="https://github.com/alchemmist/dotfiles/blob/main/wallpapers/anime/images/wallhaven-9mv6ew.jpg">this</a> and more very good stuff in my <code>dotfiles</code> repository on <a href="https://github.com/alchemmist/dotfiles/tree/main/wallpapers">GitHub</a>. Don’f forget: I love your stars!</p>

</blockquote>
<p>Let’s see:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;modules-left&#34;</span><span class="p">:</span> <span class="p">[</span><span class="err">...</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;modules-center&#34;</span><span class="p">:</span> <span class="p">[</span><span class="err">...</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;modules-left&#34;</span><span class="p">:</span> <span class="p">[</span><span class="err">...</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;modules-right&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;battery&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;custom/battery-degradation&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>First module it’s default <code>battery</code> module, for me it’s great work on hyprland. Here we define levels of good, warning and critical level of charging, define nerd icons format for different battery state:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">&#34;battery&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;states&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;good&#34;</span><span class="p">:</span> <span class="mi">90</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;warning&#34;</span><span class="p">:</span> <span class="mi">25</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;critical&#34;</span><span class="p">:</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;format&#34;</span><span class="p">:</span> <span class="s2">&#34;{icon} {capacity}%&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;format-charging&#34;</span><span class="p">:</span> <span class="s2">&#34; {capacity}%&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;format-plugged&#34;</span><span class="p">:</span> <span class="s2">&#34; {capacity}%&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;format-icons&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;󰂎&#34;</span><span class="p">,</span> <span class="s2">&#34;󰁺&#34;</span><span class="p">,</span> <span class="s2">&#34;󰁻&#34;</span><span class="p">,</span> <span class="s2">&#34;󰁼&#34;</span><span class="p">,</span> <span class="s2">&#34;󰁽&#34;</span><span class="p">,</span> <span class="s2">&#34;󰁾&#34;</span><span class="p">,</span> <span class="s2">&#34;󰁿&#34;</span><span class="p">,</span> <span class="s2">&#34;󰂀&#34;</span><span class="p">,</span> <span class="s2">&#34;󰂁&#34;</span><span class="p">,</span> <span class="s2">&#34;󰂂&#34;</span><span class="p">,</span> <span class="s2">&#34;󰁹&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;tooltip&#34;</span><span class="p">:</span> <span class="s2">&#34;{time}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;style&#34;</span><span class="p">:</span> <span class="s2">&#34;{capacity &lt; 10 ? &#39;color: red;&#39; : &#39;color: normal;&#39;}&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Second module it’s today topic: <code>custom/batterydegradaion</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">&#34;custom/battery-degradation&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;format&#34;</span><span class="p">:</span> <span class="s2">&#34; {}%&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;interval&#34;</span><span class="p">:</span> <span class="s2">&#34;once&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;exec&#34;</span><span class="p">:</span> <span class="s2">&#34;~/scripts/battery-degradation.sh&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;tooltip&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>I’m put our command to script, for me it’s useful. You can do same, don’t forgot add shebang <code>#!/bin/bash</code> and:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">chmod +x ~/scripts/battery-degradation.sh
</span></span></code></pre></div><p>In module we define the format with nerd icon and percent, turn off tooltip and set run once on waybar start <em>(because this parameter changing very long)</em>.</p>
<p>And finish this modules with css style in <code>~/.config/waybar/style.css</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">#</span><span class="nn">battery</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">#</span><span class="nn">custom-battery-degradation</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background</span><span class="p">:</span> <span class="mh">#1e1e2e</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">opacity</span><span class="p">:</span> <span class="mf">0.7</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin</span><span class="p">:</span> <span class="mi">3</span><span class="kt">px</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin-top</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span> <span class="kc">solid</span> <span class="mh">#181825</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">#</span><span class="nn">battery</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding-right</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-radius</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span> <span class="mi">0</span><span class="kt">px</span> <span class="mi">0</span><span class="kt">px</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">min-width</span><span class="p">:</span> <span class="mi">50</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">#</span><span class="nn">custom-battery-degradation</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-radius</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span> <span class="mi">10</span><span class="kt">px</span> <span class="mi">10</span><span class="kt">px</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin-right</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">min-width</span><span class="p">:</span> <span class="mi">35</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">#</span><span class="nn">battery</span><span class="p">.</span><span class="nc">critical</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="kc">red</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Done! As result:
<img
    src="/images/waybar-battery-module-2_hu_6854c9035f9f40e3.webp"
    width="151"
    height="41"
    class="content-img"
    alt=""
    loading="lazy"
    decoding="async"
  /></p>
]]></content:encoded><category>linux</category></item><item><title>Gram-Schmidt orthogonalization</title><link>https://alchemmist.xyz/articles/gram-schmidt/</link><pubDate>Sun, 06 Jul 2025 07:16:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/gram-schmidt/</guid><description>In more practical cases we want to make projection of vector to subspace, and if subspace define with orthogonal and orthonormal basis we can do it easily. To orthogonalize a vectors, we using Gram-Schmidt method.
We have source vectors $v_1, v_2, \dots, v_n$, and we need to get orthogonal vectors $u_1, u_2, \dots, u_n$. In general, describe the method: 0. Remove all zero vector.
We take first vector unchanged: $u_1 = v_1$. Next vector find from $v_2$ and projections to last vectors: $u_2 = v_2 - \text{Proj}_{u_1}{v_2}$. Again: $u_3 = v_3 - \text{Proj}_{u_1}{v_3} - \text{Proj}_{u_2}{v_3}$. And continue it to $u_n$ vector: $u_n = v_n - \text{Proj}_{u_1}{v_n} - \text{Proj}_{u_2}{v_n} - \dots - \text{Proj}_{u_{n - 1}}{v_n}$. Let’s remind how to find projection: $\text{Proj}_{u}{v} = \frac{\langle u, v\rangle}{||u||^2}u$. If we want orthonormal basis we can product all vectors $u$ to $\frac{1}{||u_i||}$. Let’s see on example: $v_1 = \begin{pmatrix}1 \\ 1\end{pmatrix}, \ v_2 = \begin{pmatrix}1 \\ 0\end{pmatrix}$. Firstly set $u_1 = v_1$, then $u_2 = v_2 - \text{Proj}_{u_1}{v_2} = \begin{pmatrix}1 \\ 0\end{pmatrix} - \begin{pmatrix}0.5 \\ 0.5\end{pmatrix} = \begin{pmatrix}0.5 \\ -0.5\end{pmatrix}$. Finally we got orthogonal vectors $u_1 = \begin{pmatrix}1 \\ 0\end{pmatrix}$, $u_2 = \begin{pmatrix}0.5 \\ -0.5\end{pmatrix}$.</description><content:encoded><![CDATA[<p>In more practical cases we want to make projection of vector to subspace, and if subspace define with orthogonal and orthonormal basis we can do it easily. To orthogonalize a vectors, we using Gram-Schmidt method.</p>
<p>We have source vectors $v_1, v_2, \dots, v_n$, and we need to get orthogonal vectors $u_1, u_2, \dots, u_n$. In general, describe the method:
0. Remove all zero vector.</p>
<ol>
<li>We take first vector unchanged: $u_1 = v_1$.</li>
<li>Next vector find from $v_2$ and projections to last vectors: $u_2 = v_2 - \text{Proj}_{u_1}{v_2}$.</li>
<li>Again: $u_3 = v_3 - \text{Proj}_{u_1}{v_3} - \text{Proj}_{u_2}{v_3}$.</li>
<li>And continue it to $u_n$ vector: $u_n = v_n - \text{Proj}_{u_1}{v_n} - \text{Proj}_{u_2}{v_n} - \dots - \text{Proj}_{u_{n - 1}}{v_n}$.
Let&rsquo;s remind how to find projection: $\text{Proj}_{u}{v} = \frac{\langle u, v\rangle}{||u||^2}u$. If we want orthonormal basis we can product all vectors $u$ to $\frac{1}{||u_i||}$.</li>
</ol>
<p>Let’s see on example: $v_1 = \begin{pmatrix}1 \\ 1\end{pmatrix}, \ v_2 = \begin{pmatrix}1 \\ 0\end{pmatrix}$.
Firstly set $u_1 = v_1$, then $u_2 = v_2 - \text{Proj}_{u_1}{v_2} = \begin{pmatrix}1 \\ 0\end{pmatrix} - \begin{pmatrix}0.5 \\ 0.5\end{pmatrix} = \begin{pmatrix}0.5 \\ -0.5\end{pmatrix}$. Finally we got orthogonal vectors $u_1 = \begin{pmatrix}1 \\ 0\end{pmatrix}$, $u_2 = \begin{pmatrix}0.5 \\ -0.5\end{pmatrix}$.</p>
]]></content:encoded><category>math</category></item><item><title>Stationary points and Lagrange method</title><link>https://alchemmist.xyz/articles/stationary-points-and-lagrange/</link><pubDate>Sun, 06 Jul 2025 05:19:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/stationary-points-and-lagrange/</guid><description>When we analyze a function, we want to find stationary points. If we haven’t a constraints, use gradient. Gradient it’s a vector of partial derivatives:
$$ \nabla f = \begin{pmatrix} \displaystyle \frac{\partial f}{\partial x_1} \\ \displaystyle \frac{\partial f}{\partial x_2} \\ \dots \\ \displaystyle \frac{\partial f}{\partial x_n} \end{pmatrix} $$See on example: $f(x, y, z) = x^2 + y^2 - 4x - 4y + z^4 - 4z^2$. Let’s find gradient:
$$ \nabla f = \begin{pmatrix} \displaystyle \frac{\partial f}{\partial x} \\ \displaystyle \frac{\partial f}{\partial y} \\ \displaystyle \frac{\partial f}{\partial z} \end{pmatrix} = \begin{pmatrix} 2x - 4 \\ 2y - 4 \\ 4z^3 - 8z \end{pmatrix} $$Then set equal to zero: $\nabla f = 0$, and got system of equations:</description><content:encoded><![CDATA[<p>When we analyze a function, we want to find stationary points. If we haven’t a constraints, use gradient. Gradient it’s a vector of partial derivatives:</p>
$$
\nabla f = \begin{pmatrix}
\displaystyle \frac{\partial f}{\partial x_1} \\
\displaystyle \frac{\partial f}{\partial x_2} \\
\dots \\
\displaystyle \frac{\partial f}{\partial x_n}
\end{pmatrix}
$$<p>See on example: $f(x, y, z) = x^2 + y^2 - 4x - 4y + z^4 - 4z^2$. Let’s find gradient:</p>
$$
\nabla f = \begin{pmatrix}
\displaystyle \frac{\partial f}{\partial x} \\
\displaystyle \frac{\partial f}{\partial y} \\
\displaystyle \frac{\partial f}{\partial z}
\end{pmatrix} =  \begin{pmatrix}
2x - 4 \\
2y - 4 \\
4z^3 - 8z
\end{pmatrix}
$$<p>Then set equal to zero: $\nabla f = 0$, and got system of equations:</p>
$$
\begin{cases}2x - 4 = 0 \\ 2y - 4 = 0 \\ 4z^3 - 8z = 0 \end{cases} \quad \Rightarrow \quad \begin{cases}x = 2\\ y = 2 \\ \left[
\begin{array}{l}
z = 0 \\
z = \sqrt{2} \\
z = -\sqrt{2}
\end{array}
\right.\end{cases}
$$<p>Finally, we got this stationary points: $(2, 2, 0), \ (2, 2, \sqrt{2}), \ (2, 2, -\sqrt{2})$.</p>
<blockquote class="markdown-blockquote">
  <p>If you want to continue analysis, use <a href="/articles/hessian-matrix/">Hessian matrix</a>.</p>

</blockquote>
<p>Now, look at case, when we have function and <strong>constraints</strong>. This is where the <strong>Lagrange multiplier method</strong> comes into play. For example, function is $f(x, y) = x^2 + y^2$ on condition $x + y = 1$. Rewrite a condition as: $g(x, y) = 0$, therefore $g(x, y) = x + y - 1$. Then, find gradients for all functions:
</p>
$$
\nabla f = \begin{pmatrix}2x \\ 2y\end{pmatrix}, \quad \nabla g = \begin{pmatrix}1 \\ 1\end{pmatrix}
$$<p>
After that, write down the Lagrange equation and solve it. In general, Lagrange equation looks like:
</p>
$$
\begin{cases}
\displaystyle \frac{\partial f}{\partial x_1} = \lambda \frac{\partial g}{\partial x_1} \\
\displaystyle \frac{\partial f}{\partial x_2} = \lambda \frac{\partial g}{\partial x_2} \\
\quad \dots \\
\displaystyle \frac{\partial f}{\partial x_n} = \lambda \frac{\partial g}{\partial x_n} \\
g(x_1, x_2, \dots x_n) = 0
\end{cases}
$$<p>
In our case:
</p>
$$
\begin{cases}2x = \lambda \cdot 1\\2y = \lambda \cdot 1\\x + y = 1\end{cases} \quad \Rightarrow \quad \begin{cases}\lambda = 2x\\\lambda = 2y\\x + y = 1\end{cases} \quad \Rightarrow \quad \begin{cases}x = y\\2x = 1\end{cases}\quad \Rightarrow \quad x = y = \frac{1}{2}
$$<p>
Done! Stationary point is $\left(\frac{1}{2}, \frac{1}{2} \right)$. Let’s resume: if functions without constraints use equation $\nabla f = 0$, else use Lagrange multiplier method.</p>
]]></content:encoded><category>math</category></item><item><title>Hessian matrix</title><link>https://alchemmist.xyz/articles/hessian-matrix/</link><pubDate>Sat, 05 Jul 2025 12:48:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/hessian-matrix/</guid><description>Imagine we got function and a few stationary points of this function, and we need to classify them, like: max, min or saddle point. If function without constraints, we can use Hessian matrix.
How to find stationary points of the function you can read at this article: “Stationary points and Lagrange method”
Let’s learn it on example. Function and stationary points: $$ f(x, y) = x^3 + y^3 - 3xy; \quad A = (0; 0), \ B = (1; 1) $$ Firstly, build Hessian matrix. In general form Hessian matrix looks like:</description><content:encoded><![CDATA[<p>Imagine we got function and a few stationary points of this function, and we need to classify them, like: max, min or saddle point. If function without constraints, we can use Hessian matrix.</p>
<blockquote class="markdown-blockquote">
  <p>How to find stationary points of the function you can read at this article: “<a href="/articles/stationary-points-and-lagrange/">Stationary points and Lagrange method</a>”</p>

</blockquote>
<p>Let’s learn it on example. Function and stationary points:
</p>
$$
f(x, y) = x^3 + y^3 - 3xy; \quad A = (0; 0), \ B = (1; 1)
$$<p>
Firstly, build Hessian matrix. In general form Hessian matrix looks like:
</p>
$$
H_f(x) =
\begin{bmatrix}
\displaystyle \frac{\partial^2 f}{\partial x_1^2} & \displaystyle \frac{\partial^2 f}{\partial x_1 \partial x_2} & \cdots & \displaystyle \frac{\partial^2 f}{\partial x_1 \partial x_n} \\
\displaystyle \frac{\partial^2 f}{\partial x_2 \partial x_1} & \displaystyle \frac{\partial^2 f}{\partial x_2^2} & \cdots & \displaystyle \frac{\partial^2 f}{\partial x_2 \partial x_n} \\
\vdots & \vdots & \ddots & \vdots \\
\displaystyle \frac{\partial^2 f}{\partial x_n \partial x_1} & \displaystyle \frac{\partial^2 f}{\partial x_n \partial x_2} & \cdots & \displaystyle \frac{\partial^2 f}{\partial x_n^2}
\end{bmatrix}
$$<p>
For our function it is: $H = \begin{bmatrix}6x & -3 \\-3 & 6y\end{bmatrix}$. Then substitute points in this matrix and find eigenvalues:
</p>
$$
\begin{align}
&H_A = \begin{bmatrix}0 & -3 \\ -3 & 0\end{bmatrix} 
&&H_B = \begin{bmatrix}6 & -3 \\ -3 & 6\end{bmatrix} 
\\[1em]
&\det(H_A - \lambda I) = 
\det \begin{bmatrix}
0 - \lambda & -3 \\
-3 & 0 - \lambda
\end{bmatrix} =
&&\det(H_B - \lambda I) = \det \begin{bmatrix}
6 - \lambda & -3 \\
-3 & 6 - \lambda
\end{bmatrix} =
\\
&= (-\lambda)(-\lambda) - (-3)(-3) = \lambda^2 - 9 = 0 \ \Rightarrow \quad \quad \quad \quad
&&= (6-\lambda)^2 - 9 = 0 \ \Rightarrow
\\[1em]
&\Rightarrow \ \lambda^2 = 9 \ \Rightarrow \  \lambda = \pm 3 \ \Rightarrow
&&\Rightarrow \ (6-\lambda)^2 = 9 \ \Rightarrow \ 6 - \lambda = \pm 3 \ \Rightarrow
\\[1em]
&\Rightarrow \lambda_1 = 3, \quad \lambda_2 = -3
&&\Rightarrow \lambda_1 = 6 - 3 = 3, \quad \lambda_2 = 6 + 3 = 9
\end{align}
$$<p>
Then use this rules:</p>
<ul>
<li>If Hessian eigenvalues is positives, point is local minimum</li>
<li>If Hessian eigenvalues is negative, point is local maximum</li>
<li>If Hessian eigenvalues not defined, point is saddle</li>
</ul>
<p>As result, point $A$ it is saddle point and point $B$ it is local minimum.</p>
]]></content:encoded><category>math</category></item><item><title>Subsapces</title><link>https://alchemmist.xyz/articles/subspaces/</link><pubDate>Thu, 03 Jul 2025 10:42:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/subspaces/</guid><description>Start with useful definition: Non-zero vectors $u, v \in \mathbb{R}$ call collinear vectors, if they are proportional to each other, that is exist $\lambda \in \mathbb{R}$, that $u = \lambda v$. Collinear vectors denoted as $u || v$. Zero-vector collinear with any vector. Geometrically, vectors collinear, if they have same or opposite direction.
Let’s consider the plane $\pi$ in $\mathbb{R}^3$ space, which passes through zero-coordinate. Consider two non-collinear vectors $u$ an $v$ from this plane. Then, any point $x \in \pi$ we can be represented as: $x = \alpha u + \beta v$.</description><content:encoded><![CDATA[<p>Start with useful definition: Non-zero vectors $u, v \in \mathbb{R}$ call <strong>collinear vectors</strong>, if they are proportional to each other, that is exist $\lambda \in \mathbb{R}$, that $u = \lambda v$. Collinear vectors denoted as $u || v$. Zero-vector collinear with any vector. Geometrically, vectors collinear, if they have same or opposite direction.</p>
<p>Let’s consider the plane $\pi$ in $\mathbb{R}^3$ space, which passes through zero-coordinate. Consider two non-collinear vectors $u$ an $v$ from this plane. Then, any point $x \in \pi$ we can be represented as: $x = \alpha u + \beta v$.</p>
<p><img
    src="/images/two-vectors-on-plane_hu_f81c1a3af72a6417.webp"
    width="1600"
    height="883"
    class="content-img" style="width:400px"
    alt=""
    loading="lazy"
    decoding="async"
  />
Okay, it’s mean we can define plane $\pi$  as:
</p>
$$
\pi = \{\text{all vectors }\  x \ \text { represented as }\ x = \alpha u + \beta v\}
$$<p>
Let’s generalize the concept of a plane passing through the origin to a space of arbitrary dimension:
The linear <strong>Span</strong> of vectors $v_1, v_2, \dots, v_k \ \in \ \mathbb{R}^n$ is called set of vectors, represented in form of sum of vectors $v_1, v_2, \dots, v_k$ with arbitrary ratio:
</p>
$$
P = \text{span}{(v_1, v_2, \dots, v_k)} = \{ x: \ x = \alpha_1 v_1 + \alpha_2 v_2 + \dots + \alpha_k v_k, \ \alpha_i \in \mathbb{R} \}.
$$<p>
Expression $\alpha_1 v_1 + \alpha_2 v_2 + \dots + \alpha_k v_k$ will call linear combination of vectors $v_1, v_2, \dots, v_k$.</p>
<p>Let’s final this with pivotal definition: <strong>linear subspace</strong> $\mathbb{R}^n$ called span of finite numbers of vectors $v_1, v_2, \dots v_k \ \in \mathbb{R}^n$:
</p>
$$
V = \text{span}(v_1, v_2, \dots, v_k)
$$<p>
The span concept and subspace concept equivalents. And any span and subspace contain a $0$, because we can make all ratio $\alpha_1, \alpha_2, \dots, \alpha_k$ equal to zero .</p>
<p>Why linear subspace is important? Here is an example:</p>
<blockquote class="markdown-blockquote">
  <p>Let us take a black-and-white digital photograph of size 512 by 512 pixels. In computer memory, this photograph can be represented as $512 \times 512 = 262144$ numbers — each representing the intensity of the corresponding pixel, ranging from 0 (completely black) to 1 (completely white). Thus, the photograph can be represented as a vector $x$ in a space of dimension $d=262144$.</p>
<p>Now, let us consider an important practical problem — compressing the photograph without significant loss. It turns out that this problem can be solved by finding a special low-dimensional subspace and projecting the vector $x$ onto this subspace.</p>

</blockquote>
<p>We told, that subspace need to contain zero. It’s mean line $y = 2x$ is a subspace, but line $y = x + 2$ not. But many properties of subspace saved when it doesn’t contain zero. Therefore, we call such subspaces as affine subspaces. <strong>Affine subspaces</strong> of $\mathbb{R}^n$ is a set of vectors $A$ of the form $a + v$, where $a \in \mathbb{R}^n$ — is a fixed vector, and vector $v$ belongs to linear subspace $V$. Let linear subspace $V$ is span of vectors $v_1, v_2, \dots, v_k$. Then, affine affine subspace is a set:
</p>
$$
A = \{ x: \ x = a + \alpha_1 v_1 + \alpha_2 v_2 + \dots + \alpha_k v_k, \ \alpha_i \in \mathbb{R}\}
$$<p>
Let $V$ — subspace in $\mathbb{R}^n$. <strong>Dimension</strong> of this subspace is minimal count of vectors $v_1, v_2, \dots, v_k \in \mathbb{R}^n$ for define subspace $V$:
</p>
$$
V = \text{span}(v_1, v_2, \dots, v_k).
$$<p>
Dimension is denoted by: $\dim{(V)}$.
Let’s think about it. For example, we have two non-collinear vectors $u, v \in \mathbb{R}^{100}$ and subspace $V = \text{span}(u, v)$. We know every vector $x \in V$ have 100 coordinates, but, by subspace definition: $x = \alpha u + \beta v$. it’s mean any vector $x$ defined only two parameters $\alpha$ and $\beta$, therefore $\dim{(V))} = 2$. For define point in $\mathbb{R}^n$ we need $n$ parameters, for define point in $V$ we need $\dim{(V)}$ parameters.</p>
<p><img
    src="/images/define-subspace_hu_d2ba0211e5bef597.webp"
    width="1600"
    height="497"
    class="content-img" style="width:800px"
    alt=""
    loading="lazy"
    decoding="async"
  /></p>
<p>Exist subspace, which defined only one vector $0$: $V = \text{span}(0)$. We call this subspace trivial, and considered $\dim{(V)} = 0$.</p>
<p>If we have subspace $V = \text{span}(v_1, v_2, \dots, v_k)$, when $\dim{(V)}$ can be smaller than $k$? if and only if one of the vectors can be express as linear combination rest vectors, for example: $v_1 = \gamma_2v_2 + \gamma_3v_3 + \dots + \gamma_kv_k$.</p>
<p>Set of vectors called <strong>linearly independent</strong> if equality:
</p>
$$
\alpha_1 v_1 + \alpha_2 v_2 + \dots + \alpha_k v_k = 0
$$<p>
holds only for $\alpha_1 = \alpha_2 = \dots = \alpha_k = 0$. If equality can be holds for non-zero rates, vectors <strong>linearly dependent</strong>.</p>
<p>Consider space $\mathbb{R}^n$ and a given non-zero vector $w \in \mathbb{R}^n$ . Then set of vectors $P$, perpendicular $w$:
</p>
$$
P = \{ \ x: \langle x;w \rangle = 0\ \}
$$<p>
is linear subspace with $\dim{(P)} = n - 1$</p>
]]></content:encoded><category>math</category></item><item><title>Line and plane</title><link>https://alchemmist.xyz/articles/line-and-plane/</link><pubDate>Sat, 28 Jun 2025 17:18:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/line-and-plane/</guid><description>The Linear Algebra starts from basic geometry intuition, which continues to multivariate spaces. Now we will talk about line, plane and space.
# The line in plane and space How to define a line in plane? Of course, through two points. But it’s not all. Exists are three more methods:
Parametric equation Let line $l$ set by two points $r_0 = (x_0; y_0)$ and $r_1 = (x_1;y_1)$. Observe that vector $a = r_0 - r_1$ in same direction with $l$. Therefore, any point on $l$ may define as $r = r_0 + ta$, where $t \in \mathbb{R}$ and full line $l$ way be with $-\infty &amp;lt; t &amp;lt; \infty$. This expression we call parametric equation:</description><content:encoded><![CDATA[<p>The Linear Algebra starts from basic geometry intuition, which continues to multivariate spaces. Now we will talk about line, plane and space.</p>

<h2 id="the-line-in-plane-and-space">
  <a class="link" href="#the-line-in-plane-and-space">
    #
  </a>
  The line in plane and space
</h2>

<p>How to define a line in plane? Of course, through two points. But it’s not all. Exists are three more methods:</p>
<ol>
<li>
<p><strong>Parametric equation</strong>
Let line $l$ set by two points $r_0 = (x_0; y_0)$ and $r_1 = (x_1;y_1)$. Observe that vector $a = r_0 - r_1$ in same direction with $l$. Therefore, any point on $l$ may define as $r = r_0 + ta$, where $t \in \mathbb{R}$ and full line $l$ way be with $-\infty < t < \infty$. This expression we call <em>parametric equation</em>:
</p>
$$
l = \{r: r = r_o + at, \ t \in \mathbb{R} \}
$$</li>
<li>
<p><strong>Linear equation</strong>
Let’s write the parametric equation using coordinates:
</p>
$$
\begin{bmatrix}x \\ y\end{bmatrix} = \begin{bmatrix}x_0\\y_0\end{bmatrix} + \begin{bmatrix}t \cdot a_1 \\ t \cdot a_2\end{bmatrix} \Rightarrow \begin{cases}x = x_0 + ta_1 \\ y = y_0 + ta_2\end{cases}
$$<p>
Suppose that, $a_1 \neq 0$ and $a_2 \neq 0$ and solve $t$ from each equation: $\frac{x - x_0}{a_1} = \frac{y - y_0}{a_2} \Rightarrow a_2x - a_1y + (a_1y_0 - a_2x_0) = 0$. Since $a_1, a_2, x_0, x_1$ it’s a numbers, that mean we can define it as linear equation:
</p>
$$
Ax + By + C = 0
$$<p>
where $A = a_2$, $B = -a_1$, $C = (a_1y_0 - a_2x_0)$</p>
</li>
<li>
<p><strong>Normal and translation</strong>
Last method. Let’s select random point on line $l$ with radius-vector $r_0$. Let’s draw a vector $n$ from point $r_0$, that is perpendicular line $l$. Then for any point $r$ on line $l$ vectors $r - r_0$ and $n$ will be perpendicular. Rewrite it with scalar product:
</p>
$$
l = \{ r: \langle r - r_0;n\rangle = 0\}
$$<p>
Of course, $r_0$ it can by any point on line $l$ and normal vector $n$ any vector perpendicular to line $l$. To find normal to line, we need direction vector $a = \begin{pmatrix}a_1 \\ a_2\end{pmatrix}$ from <em>parametric equation</em> and then normal vector will be: $n = \begin{bmatrix}-a_2\\ a_1\end{bmatrix}$ or $n’ = -n = \begin{bmatrix} a_2 \\ -a_1\end{bmatrix}$</p>
</li>
</ol>
<p>Let’s resume and see the relationship between this methods. If line passes through two points $r_0 = (x_0; y_0)$ and $r_1 = (x_1; y_1)$, then his can be define of of the three methods:</p>
<ul>
<li>parametric equation :

$$
r = r_0 + ta = \begin{bmatrix}x_0\\y_0\end{bmatrix} + t \cdot \begin{bmatrix}x_1 - x_0 \\ y_1 - y_0\end{bmatrix} = \begin{bmatrix}x_0\\y_0\end{bmatrix} + \begin{bmatrix}t \cdot a_1 \\ t \cdot a_2\end{bmatrix}
$$</li>
<li>linear equation:

$$
Ax + By + C = 
\underbrace{a_2}_{A} x + 
\underbrace{(-a_1)}_{B} y + 
\underbrace{(a_1 y_0 - a_2 x_0)}_{C} = 0;
$$</li>
<li>normal and translation:

$$
\langle r - r_0; n\rangle = \left\langle \begin{bmatrix}x - x_0\\y - y_0\end{bmatrix}; \begin{bmatrix}a_1 \\ -a_1\end{bmatrix}\right\rangle = \left\langle\begin{bmatrix}x - x_0 \\ y - y_0\end{bmatrix}; \begin{bmatrix}A \\ B\end{bmatrix} \right\rangle
$$
What about line in space? Parametric equation doesn’t change, one vectors will get longer. Linear equation will change: now it’s not one equation, it’s system of two equations:

$$
\begin{cases}
a_2x - a_1y + (a_1y_0 - a_2x_0) = 0 \\
a_3y - a_2z + (a_2z_0 - a_3y_0) = 0
\end{cases}
$$
Method with normal and translation <strong>not working in space</strong>!</li>
</ul>
<p>Addition: let’s take to look at <strong>distance from point to line:</strong>
</p>
$$
d(P, l) = \frac{|Ax_0 + By_0 + C|}{\sqrt{A^2 + B^2}}
$$<p>
And we can detect where point relative to a line: group of points from one side, for which $Ax +By + C > 0$ is true; group from another side, for which $Ax +By + C < 0$ is true.</p>

<h2 id="the-plane-in-space">
  <a class="link" href="#the-plane-in-space">
    #
  </a>
  The plane in space
</h2>

<p>Again this question. How to define a plane in space? Of course, through with three points non-collinear, that do not lie on the same straight line. <strong>Collinear points</strong> lie on the same line. And again let’s consider three methods:</p>
<ol>
<li><strong>Parametric equation</strong>:

$$
\pi = \{r: r = r_0 + t_1v_1 + t_2v_2, \quad t_1, t_2 \in \mathbb{R}\}
$$</li>
<li><strong>Normal and translation</strong> is the same as for line: $\langle r - r_0; n\rangle = 0$</li>
<li><strong>Linear equation:</strong> start from normal and translation and expand it:

$$
\langle r - r_0; n\rangle = 0 \quad \Rightarrow \quad 
\underbrace{n_1}_{A} x\  + \ 
\underbrace{n_2}_{B} y\  + \
\underbrace{n_3}_{C} z \ 
\underbrace{- \langle r_0 ;n\rangle}_{D} = 0. \ \Rightarrow \ Ax + By + Cz + D = 0
$$
Let’s look to relationship between this methods:</li>
</ol>
<ul>
<li>For rewrite parametric equation to normal and translation we need to find normal vector from this system of equations: $\begin{cases}\langle n; v_1\rangle = 0 \\ \langle n; v_2\rangle = 0\end{cases}$</li>
<li>For rewrite normal and translation form to linear equation we can use this: $A = n_1$, $B = n_2$, $C = n_3$, $D = -\langle n ;r_0\rangle$</li>
<li>If we have three points, defined plane, we can go to parametric equation: $\begin{array}a v_1 = r_1 - r_0\\ v_2 = r_2 - r_0\end{array}$</li>
</ul>
<p>Projection point $P$ on plan $\pi$ we call point $P_\pi \in \pi$, the closest to the point $P$: $P_\pi = \arg{\min{||P - X||}}, \ X \in \pi$. Then, the distance from point $P$ to plane $\pi$ will be $d(P, \pi)$ — the distance between point $P$ and her projection $P_\pi$:
</p>
$$
d(P, \pi) = \frac{|Ax_0 + By_0 + Cz_0 + D|}{\sqrt{A^2 + B^2 + C^2}}
$$<p>
Detecting where point relative a plane is the same as line.</p>
]]></content:encoded><category>math</category></item><item><title>Base of multivariate vectors</title><link>https://alchemmist.xyz/articles/multivariate-vectors/</link><pubDate>Thu, 26 Jun 2025 14:18:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/multivariate-vectors/</guid><description>What is a vector? For natural number $n$ will call a n-variate vector list of n ordered real numbers $v = \begin{pmatrix}v_1&amp;amp;v_2&amp;amp;v_3&amp;amp;\ldots&amp;amp;v_n\end{pmatrix}$. Well the $n$ number is a vector dimension: $\dim{v} = n$. For $n$ number the set of all possible vectors will call $R^n$. The regular number we call “scalar”. For example, $5 \ - \ scalar$, but $\begin{pmatrix}1&amp;amp;3\end{pmatrix} \ - \ vector$.
# The basic operations of vectors Sum of vectors is a sum of corresponding coordinates: $$ v + w = \begin{pmatrix}v_1 \\ v_2 \\ \ldots \\ v_n \end{pmatrix} + \begin{pmatrix}w_1 \\ w_2 \\ \ldots \\ w_n \end{pmatrix} = \begin{pmatrix}v_1 + w_1 \\ v_2 + w_2 \\ \ldots \\ v_n + w_n \end{pmatrix} $$ We can add vectors only they have same dimension. 2. Product of vector by scalar is a product off each coordinates by a scalar:</description><content:encoded><![CDATA[<p>What is a vector? For natural number $n$ will call a n-variate <strong>vector</strong> list of n ordered real numbers $v = \begin{pmatrix}v_1&v_2&v_3&\ldots&v_n\end{pmatrix}$. Well the $n$ number is a vector dimension: $\dim{v} = n$. For $n$ number the set of all possible vectors will call $R^n$.
The regular number we call “scalar”. For example, $5 \ - \ scalar$, but $\begin{pmatrix}1&3\end{pmatrix} \ - \ vector$.</p>

<h2 id="the-basic-operations-of-vectors">
  <a class="link" href="#the-basic-operations-of-vectors">
    #
  </a>
  The basic operations of vectors
</h2>

<ol>
<li>Sum of vectors is a sum of corresponding coordinates:

$$
v + w = \begin{pmatrix}v_1 \\ v_2 \\ \ldots \\ v_n \end{pmatrix} + \begin{pmatrix}w_1 \\ w_2 \\ \ldots \\ w_n \end{pmatrix} = \begin{pmatrix}v_1 + w_1 \\ v_2 + w_2 \\ \ldots \\ v_n + w_n \end{pmatrix}
$$</li>
</ol>
<p>We can add vectors only they have same dimension.
2. Product of vector by scalar is a product off each coordinates by a scalar:
</p>
$$
\lambda v = \lambda \cdot \begin{pmatrix}v_1 \\ v_2 \\ \ldots \\ v_n \end{pmatrix} = \begin{pmatrix}\lambda v_1 \\ \lambda v_2 \\ \ldots \\ \lambda v_n \end{pmatrix}
$$<p>
3. Difference of vectors is a sum of vectors, but one of vector product by scalar $-1$.
4. Scalar product of vectors:
</p>
$$
x \cdot y = \langle x;y\rangle = x_1 y_1 + x_2 y_2 + \ldots + x_n y_n = \sum \limits_{i = 1}^{n}x_i y_i
$$<p>
Properties of scalar vectors product:</p>
<ul>
<li>Commutativity: $\langle v; w\rangle = \langle w; v\rangle$</li>
<li>Distributivity over addition: $\langle x; (v + w)\rangle = \langle x; v\rangle + \langle x; w \rangle$</li>
<li>Compatibility with scalar multiplication: $\langle v; \lambda w\rangle = \lambda \langle v;w\rangle$</li>
<li>If scalar product equal zero we call this two vectors <em>orthogonal</em> or <em>perpendicular</em></li>
</ul>

<h2 id="geometric-meaning">
  <a class="link" href="#geometric-meaning">
    #
  </a>
  Geometric meaning
</h2>

<p>In geometry vector is a segment having a direction.
<img
    src="/images/the-vector_hu_3dba13051fbe9e9b.webp"
    width="984"
    height="628"
    class="content-img" style="width:400px"
    alt=""
    loading="lazy"
    decoding="async"
  /></p>
<p>The <strong>length</strong> of vector we calculate with Pythagoras’s theorem: $||v|| = \sqrt{\sum\limits_{i = 1}^{n}{x_i}}$. If length of vector equal one we call it a <strong>unit vector</strong>. If $v$ not a unit vector we can change it multiplying by $\lambda = \frac{1}{||v||}$. We can calculate distance and angle between two vectors.  <strong>Distance</strong> is a length of difference two vectors: $d = ||v - w|| = \sqrt{\sum\limits_{i = 1}^{n}{(v_i - w_i)^2}}$. <strong>Angle</strong> between two vectors follows from Law of Cosines:
</p>
$$
\cos{\theta} = \frac{\langle u;b \rangle}{||u||\ ||v||}
$$<p>
Often be helpful: $||u|| = \sqrt{\langle u;u\rangle}$. Next operation is <strong>projection vector $u$ to vector $w$</strong>:
</p>
$$
Proj_w(u) = \frac{\langle u;w\rangle}{||w||^2}w
$$<p>
Another property of vectors: module of scalar product does not exceed product of their length — the <strong>Cauchy–Schwarz inequality</strong>:
</p>
$$
-||v||\ ||w|| \leqslant \langle v;w\rangle \leqslant ||v||\ ||w||
$$<p>
The <strong>Triangle inequality:</strong> $||v + w|| \leqslant ||v|| + ||w||$, so length of sum of vectors less than or equal to sum of vectors lengths. If vectors is orthogonal, work the Pythagoras’s theorem: $||a + b||^2 = ||a||^2 + ||b||^2$.</p>
]]></content:encoded><category>math</category></item><item><title>Transparent Deployment with GitHub Actions</title><link>https://alchemmist.xyz/articles/deploy-gh-actions/</link><pubDate>Tue, 24 Jun 2025 14:18:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/deploy-gh-actions/</guid><description>Recently, find the simple way to make anything at my servers in GitHub pipeline with Actions. And I love it’s very clear. I can control all operations, step and processes. Now I’ll show how to make clear depoly with it, but you can use similar for your goals.
Let’s think! How we deploy manually? In the simple case, we connect to server, pull repository and then restart our app. We want automate all of this. Let’s start with first point. We connect to server with SSH, but what we need to do it? Often connection looks like this:</description><content:encoded><![CDATA[<p>Recently, find the simple way to make anything at my servers in GitHub pipeline with Actions. And I love it’s very clear. I can control all operations, step and processes. Now I’ll show how to make clear depoly with it, but you can use similar for your goals.</p>
<p>Let’s think! How we deploy manually? In the simple case, we connect to server, pull repository and then restart our app.
<img src="/images/deploy-pipeline.svg" class="content-img" style="width:500px" alt="" loading="lazy" decoding="async" />
We want automate all of this. Let’s start with first point. We connect to server with SSH, but what we need to do it? Often connection looks like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">ssh root@192.168.0.1 -i ~/.ssh/id_rsa25519
</span></span></code></pre></div><p>Here i have three information unit for get access:</p>
<ol>
<li>Server IP address</li>
<li>Username of user</li>
<li>SSH private key
We make “clear” deployment, therefore all step in our manually pipeline will be automate. In order to GitHub Actions can connect to our server we need to give all information. GitHub have special entity for it: <code>Secrets and Variables</code> now, for more security we put all to <code>secrets</code>.</li>
</ol>
<p>Open your GitHub repository and go to <code>Settings</code>, here in <code>Security</code> section click to <code>Secrets and Variables</code> and go to <code>Actions</code>. Then we will add three secrets: <code>SSH_USER</code>, <code>SSH_HOST</code>, <code>SSH_KEY</code>.  Remember, the public pair of <code>SSH_KEY</code> private key need to be added to <code>~/.ssh/authorized_keys</code> on server. Nice! First step was finished.</p>
<p>Next we need to pull repository. If your server is clean, you need to firstly clone it. If your repository is private, most likely, when you try to do it, you got something like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">git@github.com: Permission denied (publickey).
</span></span><span class="line"><span class="cl">fatal: Could not read from remote repository.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Please make sure you have the correct access rights
</span></span><span class="line"><span class="cl">and the repository exists.
</span></span></code></pre></div><p>You need to generate <em>(or migrate)</em> the ssh keys on your server. For generate you can use this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">ssh-keygen -C github -t ed25519
</span></span></code></pre></div><p>Then copy <code>~/.ssh/id_ed25519.pub</code> and copy on GitHub repository settings at <code>Deploy keys</code>. After you can clone repository. In order to GitHub Actions know where your project we make new secret <code>SSH_PROJECT_PATH</code>.</p>
<p>Last step: GitHub Actions. Restart service or anything steps, what you want, we describe <code>.gitub/workflows/deploy.yaml</code> <em>(file name doesn’t matter)</em>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Deploy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">deploy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Pull repo</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">appleboy/ssh-action@master</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">host</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.SSH_HOST }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">username</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.SSH_USER }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">key</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.SSH_KEY }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">script</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">            cd ${{ secrets.SSH_PROJECT_PATH }}
</span></span></span><span class="line"><span class="cl"><span class="sd">            git pull origin main --rebase</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Compose down</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">appleboy/ssh-action@master</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">host</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.SSH_HOST }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">username</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.SSH_USER }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">key</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.SSH_KEY }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">script</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">            cd ${{ secrets.SSH_PROJECT_PATH }}
</span></span></span><span class="line"><span class="cl"><span class="sd">            docker compose down</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Compose up</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">appleboy/ssh-action@master</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">host</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.SSH_HOST }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">username</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.SSH_USER }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">key</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.SSH_KEY }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">script</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">            cd ${{ secrets.SSH_PROJECT_PATH }}
</span></span></span><span class="line"><span class="cl"><span class="sd">            docker compose up -d</span><span class="w">
</span></span></span></code></pre></div><p>In this example I’m using docker for restart my services. Choose your way!</p>
]]></content:encoded><category>github</category></item><item><title>Linux disk clean up</title><link>https://alchemmist.xyz/articles/linux-clean-up/</link><pubDate>Sun, 02 Feb 2025 14:18:00 +0300</pubDate><dc:creator>alchemmist</dc:creator><guid>https://alchemmist.xyz/articles/linux-clean-up/</guid><description>If you using docker on your machine, would be a good place for start it’s clean all docker stuff. Only if you’re sure in your docker containers, volumes nothing important:
docker system prune # 1. Clean packages Next tips for Arch-base systems:
Find heaviest packages. This command show top-20 most heavy packages:
pacman -Qi | awk &amp;#39;/^Name/{name=$3} /^Installed Size/{print $4 $5, name}&amp;#39; | sort -hr | head -n 20 Find unused dependencies:</description><content:encoded><![CDATA[<p>If you using docker on your machine, would be a good place for start it’s clean all docker stuff. Only if you’re sure in your docker containers, volumes nothing important:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">docker system prune
</span></span></code></pre></div>
<h2 id="1--clean-packages">
  <a class="link" href="#1--clean-packages">
    #
  </a>
  1.  Clean packages
</h2>

<p>Next tips for Arch-base systems:</p>
<p>Find heaviest packages. This command show top-20 most heavy packages:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">pacman -Qi <span class="p">|</span> awk <span class="s1">&#39;/^Name/{name=$3} /^Installed Size/{print $4 $5, name}&#39;</span> <span class="p">|</span> sort -hr <span class="p">|</span> head -n <span class="m">20</span>
</span></span></code></pre></div><p>Find unused dependencies:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">pacman -Qdtq
</span></span></code></pre></div><p><strong>Pay attention</strong>, in this list can be important packages for you, that are no one is using, it’s doesn’t mean this need to be remove.</p>
<p>If you’re sure, you can be remove all this list:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">sudo pacman -Rns <span class="k">$(</span>pacman -Qdtq<span class="k">)</span>
</span></span></code></pre></div><p>Find forgotten packages. This command show top-20 long-unused packages:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">expac --timefmt<span class="o">=</span><span class="s1">&#39;%Y-%m-%d %T&#39;</span> <span class="s1">&#39;%l %n&#39;</span> <span class="p">|</span> sort <span class="p">|</span> head -n <span class="m">20</span>
</span></span></code></pre></div><p>Clean pacman cache. This command remove all old versions of packages, apart from last and current:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">sudo paccache -r
</span></span></code></pre></div><p>This command remove all packages, apart from current installed:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">sudo paccache -r -k <span class="m">0</span>
</span></span></code></pre></div><p>Keep in mind, after that you can be rollback to old package version without internet.</p>

<h2 id="2-clean-files">
  <a class="link" href="#2-clean-files">
    #
  </a>
  2. Clean files
</h2>

<p>This command show top-15 the heaviest directories at <code>home</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">du -h ~/ --max-depth<span class="o">=</span><span class="m">1</span> <span class="p">|</span> sort -hr <span class="p">|</span> head -n <span class="m">15</span>
</span></span></code></pre></div><p>This command show top-20 the heaviest directories at <code>home</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">find ~/ -type f -exec du -Sh <span class="o">{}</span> + <span class="p">|</span> sort -rh <span class="p">|</span> head -n <span class="m">20</span>
</span></span></code></pre></div><p>I think that’s two command enough to do all clean up what you want. You can find heavies directory at home, than go here. Then again run command for this directory. Then go to heaviest, then find heavy files…</p>
]]></content:encoded><category>linux</category></item></channel></rss>