<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Nskm</title>
    <subtitle>Never stray from the way.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://nskm.xyz/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://nskm.xyz"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-03-05T00:00:00+00:00</updated>
    <id>https://nskm.xyz/atom.xml</id>
    <entry xml:lang="en">
        <title>From rsync to CI&#x2F;CD: automating a static site deployment</title>
        <published>2026-03-05T00:00:00+00:00</published>
        <updated>2026-03-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/mvln2/"/>
        <id>https://nskm.xyz/posts/mvln2/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/mvln2/">&lt;img style=&quot;display: block; margin: 0 auto; width: 700px&quot; src=&quot;&#x2F;images&#x2F;praying_ci_god.jpeg&quot; alt=&quot;Praying the CI&#x2F;CD god&quot; title=&quot;Praying the CI&#x2F;CD god&quot;&#x2F;&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h2 id=&quot;disclaimers&quot;&gt;Disclaimers&lt;&#x2F;h2&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Opinions&lt;&#x2F;strong&gt;: The views expressed here are my own unless otherwise specified. They do not represent any employer, organization, or affiliated group.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scope&lt;&#x2F;strong&gt;: This case study documents my personal journey automating a static Zola site. Your infrastructure needs may differ.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Audience&lt;&#x2F;strong&gt;: This article assumes DevOps familiarity. You should be comfortable with Docker, shell scripts, git workflows, and Linux administration.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Testing environment&lt;&#x2F;strong&gt;: Everything in this article was tested on Ubuntu (WSL2 on Windows) running locally, and deployed to the cheapest DigitalOcean.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Thanks a million to &lt;a href=&quot;https:&#x2F;&#x2F;morgan.zoemp.be&#x2F;about&#x2F;&quot;&gt;Morgan&lt;&#x2F;a&gt; alias &lt;em&gt;SansGuidon&lt;&#x2F;em&gt; online. He took the time to tell me that I broke my atom.xml file during this experiment.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h2 id=&quot;hook&quot;&gt;Hook&lt;&#x2F;h2&gt;
&lt;p&gt;If I recall correctly, I started writing tech articles somewhere around 2014. During all those years, my deployment workflow was delightfully simple: some Markdown files, two &lt;code&gt;make&lt;&#x2F;code&gt; commands, and my static site was live. It worked. It was fast. It required zero external infrastructure.&lt;&#x2F;p&gt;
&lt;p&gt;The irony? I spent years and years toying with CI&#x2F;CD pipelines for employers, using all the modern &lt;em&gt;(and all the very old)&lt;&#x2F;em&gt; tooling. Yet my &lt;em&gt;own&lt;&#x2F;em&gt; site ran like it was 2005. &lt;em&gt;What a world!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I sincerely believe that there was no good reason to change. I only did it for fun and to entertain myself a little (&lt;em&gt;and maybe, maybe, to improve things a little bit&lt;&#x2F;em&gt;). This is the story of how I did it: from a &lt;code&gt;git push&lt;&#x2F;code&gt; on my local machine to a fully built, containerized, deployed site on a fresh server, with automatic TLS. &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=82-P9ZNYnik&quot;&gt;Music \o&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;toc&quot;&gt;ToC&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#journey&quot;&gt;The journey: where we were vs where we are going&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#gitlab-ci&quot;&gt;GitLab CI pipeline&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#gitlab-ci-config&quot;&gt; The GitLab CI configuration file&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#gitlab-ci-vars&quot;&gt; Required GitLab CI&#x2F;CD variables&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#gitlab-registry&quot;&gt; GitLab container registry&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#notification&quot;&gt; Notification mechanism: GitLab CI SSHes directly into VPS&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#container-image&quot;&gt;The Container image&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#dockerfile&quot;&gt; The multi-stage Container file&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#nginx-config&quot;&gt; The Nginx configuration file&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#vps-provisioning&quot;&gt;The VPS provisioning&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#droplet&quot;&gt; Droplet recommendation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#provisioning-steps&quot;&gt; Provisioning steps&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#vps-hardening&quot;&gt; VPS security hardening&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#doctl&quot;&gt; Going further: one-command provisioning with doctl&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#deploy-script&quot;&gt; Deploy script&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#podman-critical&quot;&gt; Critical: rootless Podman and SSH session lifecycle&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#ssl-tls&quot;&gt;SSL &amp;amp; Let&#x27;s Encrypt&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#caddy&quot;&gt; Decision: Caddy&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#letsencrypt-ip&quot;&gt; Let&#x27;s Encrypt IP address certificates&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#operations&quot;&gt;Operations&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#rollback&quot;&gt; Rollback procedure&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#image-scanning&quot;&gt; Container image security scanning&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#monitoring&quot;&gt; Uptime monitoring&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#zero-downtime&quot;&gt; Zero-downtime deploys&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;mvln2&#x2F;#more&quot;&gt;More on this topic&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;journey&quot;&gt;The journey&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;where-i-was-simple-short-deployment&quot;&gt;Where I was, simple&#x2F;short deployment&lt;&#x2F;h3&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;publish:
&lt;&#x2F;span&gt;&lt;span&gt;	zola build
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;rsync_deploy_site:
&lt;&#x2F;span&gt;&lt;span&gt;	zola build
&lt;&#x2F;span&gt;&lt;span&gt;	find public -name &amp;quot;*.xml&amp;quot; -o -name &amp;quot;*.html&amp;quot; | xargs sed -i -e &amp;#39;&#x2F;\&amp;amp;lt;!--.*--\&amp;amp;gt;&#x2F;d&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;	rsync -P -a -v --recursive -e &amp;quot;ssh -p $(SSH_PORT)&amp;quot; $(OUTPUTDIR)&#x2F; $(SSH_NICK):$(SSH_SITE_DIR) --cvs-exclude
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;.PHONY: help publish rsync_deploy_site 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Simple deployment because it involved 3 tools. Short deployment because there was a straight, direct path between my laptop and the server. I built the site locally and pushed the output directly to the VPS via rsync over SSH. The Makefile orchestrates everything — it runs &lt;code&gt;zola build&lt;&#x2F;code&gt; and then calls &lt;code&gt;rsync&lt;&#x2F;code&gt; to copy the &lt;code&gt;public&#x2F;&lt;&#x2F;code&gt; directory to the server. That&#x27;s it.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;[Local Machine]
&lt;&#x2F;span&gt;&lt;span&gt;      |
&lt;&#x2F;span&gt;&lt;span&gt;      | 1. make publish
&lt;&#x2F;span&gt;&lt;span&gt;      |    └─ zola build  →  generates public&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;      |
&lt;&#x2F;span&gt;&lt;span&gt;      | 2. make rsync_deploy_site
&lt;&#x2F;span&gt;&lt;span&gt;      |    └─ rsync -a public&#x2F; mlvn@1.2.3.4:&#x2F;home&#x2F;mlvn&#x2F;public (via SSH, port 1022)
&lt;&#x2F;span&gt;&lt;span&gt;      |
&lt;&#x2F;span&gt;&lt;span&gt;      v
&lt;&#x2F;span&gt;&lt;span&gt;[DigitalOcean VPS]
&lt;&#x2F;span&gt;&lt;span&gt;  &#x2F;home&#x2F;mlvn&#x2F;public&#x2F;   ← raw static files on disk that are served by Nginx
&lt;&#x2F;span&gt;&lt;span&gt;      |
&lt;&#x2F;span&gt;&lt;span&gt;      v
&lt;&#x2F;span&gt;&lt;span&gt;[Nginx&#x2F;web server on VPS]
&lt;&#x2F;span&gt;&lt;span&gt;  Handles TLS (Let&amp;#39;s Encrypt, auto-renewed)
&lt;&#x2F;span&gt;&lt;span&gt;  serves files directly from disk
&lt;&#x2F;span&gt;&lt;span&gt;      |
&lt;&#x2F;span&gt;&lt;span&gt;      v
&lt;&#x2F;span&gt;&lt;span&gt;[Visitor&amp;#39;s browser]
&lt;&#x2F;span&gt;&lt;span&gt;  https:&#x2F;&#x2F;nskm.xyz
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There were no external dependencies, no container images to build, no container registries to manage, no GitLab CI runners to wait for. Life was beautiful.&lt;&#x2F;p&gt;
&lt;p&gt;But... I did realize, &lt;em&gt;maaybe&lt;&#x2F;em&gt; I need a way to roll back a bad deployment. &lt;em&gt;Maaaybe&lt;&#x2F;em&gt; I need some version control. &lt;em&gt;Maaaaaybe&lt;&#x2F;em&gt; it&#x27;s not a good idea to have the source code living only on my laptop. &lt;em&gt;Maaaaaaaaybe&lt;&#x2F;em&gt; I need the build process to be reproducible. I mean, &lt;em&gt;come on man, I can do better&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;img style=&quot;display: block; margin: 0 auto; width: 500px&quot; src=&quot;&#x2F;images&#x2F;was_not_that_bad.png&quot; alt=&quot;When you take a step back, you realise that we have come a very long way.&quot; title=&quot;When you take a step back, you realise that we have come a very long way.&quot;&#x2F;&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;where-i-am-right-now-slightly-more-complex-deployment&quot;&gt;Where I am right now, slightly more complex deployment&lt;&#x2F;h3&gt;
&lt;p&gt;I do a git push to &lt;a href=&quot;https:&#x2F;&#x2F;raccoon.onyxbits.de&#x2F;blog&#x2F;why-not-use-github&quot;&gt;GitLab&lt;&#x2F;a&gt;. Everything else happens automagically: CI builds the HTML pages from the Markdown files, CI builds a Docker image containing the compiled site, then pushes it to the &lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;user&#x2F;packages&#x2F;container_registry&#x2F;&quot;&gt;GitLab Container Registry&lt;&#x2F;a&gt; and finally, SSHes into the VPS to pull and run the new image. &lt;a href=&quot;https:&#x2F;&#x2F;caddyserver.com&#x2F;&quot;&gt;Caddy&lt;&#x2F;a&gt; on the VPS handles TLS termination and proxies traffic to the container.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;[Local Machine]
&lt;&#x2F;span&gt;&lt;span&gt;      |
&lt;&#x2F;span&gt;&lt;span&gt;      | git push origin master
&lt;&#x2F;span&gt;&lt;span&gt;      |
&lt;&#x2F;span&gt;&lt;span&gt;      v
&lt;&#x2F;span&gt;&lt;span&gt;[GitLab.com]
&lt;&#x2F;span&gt;&lt;span&gt;  Repository stores all source: content&#x2F;, templates&#x2F;, sass&#x2F;, themes&#x2F;, config.toml
&lt;&#x2F;span&gt;&lt;span&gt;      |
&lt;&#x2F;span&gt;&lt;span&gt;      | .gitlab-ci.yml triggers pipeline automatically
&lt;&#x2F;span&gt;&lt;span&gt;      |
&lt;&#x2F;span&gt;&lt;span&gt;      ├─ Stage 1: build-and-push-image
&lt;&#x2F;span&gt;&lt;span&gt;      |    ├─ docker:dind runner
&lt;&#x2F;span&gt;&lt;span&gt;      |    ├─ zola build  (inside Dockerfile, Stage 1: debian:bookworm-slim)
&lt;&#x2F;span&gt;&lt;span&gt;      |    ├─ output copied into nginx:alpine image  (Stage 2)
&lt;&#x2F;span&gt;&lt;span&gt;      |    ├─ image built and tagged: registry.gitlab.com&#x2F;USERNAME&#x2F;proj:&amp;lt;commit-sha&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      |    └─ image pushed to GitLab Container Registry
&lt;&#x2F;span&gt;&lt;span&gt;      |
&lt;&#x2F;span&gt;&lt;span&gt;      └─ Stage 2: deploy-to-vps
&lt;&#x2F;span&gt;&lt;span&gt;           ├─ alpine runner with openssh-client
&lt;&#x2F;span&gt;&lt;span&gt;           └─ SSH into VPS → runs &#x2F;home&#x2F;mlvn&#x2F;deploy.sh &amp;lt;commit-sha&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;                |
&lt;&#x2F;span&gt;&lt;span&gt;                v
&lt;&#x2F;span&gt;&lt;span&gt;[DigitalOcean VPS — new Droplet]
&lt;&#x2F;span&gt;&lt;span&gt;  deploy.sh:
&lt;&#x2F;span&gt;&lt;span&gt;    podman pull registry.gitlab.com&#x2F;USERNAME&#x2F;proj:&amp;lt;sha&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    podman stop nskm-site  (old container)
&lt;&#x2F;span&gt;&lt;span&gt;    podman run -d --name nskm-site -p 8080:80 IMAGE:&amp;lt;sha&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;      |
&lt;&#x2F;span&gt;&lt;span&gt;      v
&lt;&#x2F;span&gt;&lt;span&gt;[Caddy on VPS host]
&lt;&#x2F;span&gt;&lt;span&gt;  Handles TLS (Let&amp;#39;s Encrypt, auto-renewed)
&lt;&#x2F;span&gt;&lt;span&gt;  Caddyfile: reverse_proxy localhost:8080
&lt;&#x2F;span&gt;&lt;span&gt;      |
&lt;&#x2F;span&gt;&lt;span&gt;      v
&lt;&#x2F;span&gt;&lt;span&gt;[Visitor&amp;#39;s browser]
&lt;&#x2F;span&gt;&lt;span&gt;  https:&#x2F;&#x2F;nskm.xyz
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Pros of the CI&#x2F;CD approach&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;I just git push code, site deploys itself&lt;&#x2F;li&gt;
&lt;li&gt;Version controlled: full git history, every change is tracked and auditable&lt;&#x2F;li&gt;
&lt;li&gt;Rollback: any previous image tag can be redeployed in seconds&lt;&#x2F;li&gt;
&lt;li&gt;Immutable deploys: each deploy is a fresh container from a known image, no partial file transfers&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Cons of the CI&#x2F;CD approach&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;More moving parts, more things that can break: GitLab, container registry, Docker&#x2F;Podman, Caddy, deploy script&lt;&#x2F;li&gt;
&lt;li&gt;Slower feedback loop: pipeline takes more minutes&lt;&#x2F;li&gt;
&lt;li&gt;Registry storage to manage: images accumulate (mitigated by cleanup policy)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;img style=&quot;display: block; margin: 0 auto; width: 400px&quot; src=&quot;&#x2F;images&#x2F;ci_down.webp&quot; alt=&quot;CI is down&quot; title=&quot;CI is down&quot;&#x2F;&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;gitlab-ci&quot;&gt;GitLab CI pipeline&lt;&#x2F;h2&gt;
&lt;p&gt;TODO: gitlab ci file ???&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gitlab-ci-config&quot;&gt;The GitLab CI configuration file: &lt;code&gt;.gitlab-ci.yml&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Nothing fancy:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;image&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;docker:24.0.5-cli&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;docker:24.0.5-dind&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;variables&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;DOCKER_TLS_CERTDIR&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;certs&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;DOCKER_TLS_VERIFY&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;DOCKER_CERT_PATH&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;$DOCKER_TLS_CERTDIR&#x2F;client&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;DOCKER_DRIVER&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;overlay2&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;DOCKER_BUILDKIT&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;IMAGE_NAME&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;registry.gitlab.com&#x2F;$CI_PROJECT_NAMESPACE&#x2F;$CI_PROJECT_NAME&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;IMAGE_TAG&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;$CI_COMMIT_SHORT_SHA&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;stages&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;build-and-push&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;deploy&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;build-and-push-image&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;stage&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;build-and-push&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;before_script&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;docker login -u &amp;quot;$CI_REGISTRY_USER&amp;quot; -p &amp;quot;$CI_REGISTRY_PASSWORD&amp;quot; &amp;quot;$CI_REGISTRY&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;docker build&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;--cache-from &amp;quot;${IMAGE_NAME}:latest&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;--build-arg BUILDKIT_INLINE_CACHE=1&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;-t &amp;quot;${IMAGE_NAME}:${IMAGE_TAG}&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;-t &amp;quot;${IMAGE_NAME}:latest&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;.
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;docker push &amp;quot;${IMAGE_NAME}:${IMAGE_TAG}&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;docker push &amp;quot;${IMAGE_NAME}:latest&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;rules&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;$CI_COMMIT_BRANCH == &amp;quot;master&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;deploy-to-vps&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;stage&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;deploy&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;image&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;alpine:3.19&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;before_script&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;apk add --no-cache openssh-client&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;eval $(ssh-agent -s)&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;echo &amp;quot;$MLVN_SSH_PRIVATE_KEY&amp;quot; | tr -d &amp;#39;\r&amp;#39; | base64 -d | ssh-add -&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;mkdir -p ~&#x2F;.ssh &amp;amp;&amp;amp; chmod 700 ~&#x2F;.ssh&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;echo &amp;quot;$MLVN_SSH_KNOWN_HOST&amp;quot; &amp;gt;&amp;gt; ~&#x2F;.ssh&#x2F;known_hosts&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;ssh -p 1234 mlvn@$MLVN_IP &amp;quot;&#x2F;home&#x2F;mlvn&#x2F;deploy.sh ${IMAGE_TAG}&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;needs&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;build-and-push-image&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;rules&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;$CI_COMMIT_BRANCH == &amp;quot;master&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;environment&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;production&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;url&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;https:&#x2F;&#x2F;nskm.xyz&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;gitlab-ci-vars&quot;&gt;Required GitLab CI&#x2F;CD variables&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Variable&lt;&#x2F;th&gt;&lt;th&gt;Type&lt;&#x2F;th&gt;&lt;th&gt;Protected&lt;&#x2F;th&gt;&lt;th&gt;Masked&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;VPS_SSH_PRIVATE_KEY&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Variable (private key content)&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;VPS_IP&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Variable (new Droplet IP once known)&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;VPS_IP&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Variable (new Droplet IP once known)&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;All other needed variables (&lt;code&gt;CI_REGISTRY_USER&lt;&#x2F;code&gt;, &lt;code&gt;CI_REGISTRY_PASSWORD&lt;&#x2F;code&gt;, &lt;code&gt;CI_REGISTRY&lt;&#x2F;code&gt;, &lt;code&gt;CI_COMMIT_SHORT_SHA&lt;&#x2F;code&gt;, etc.) are injected automatically by GitLab.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gitlab-registry&quot;&gt;GitLab container registry&lt;&#x2F;h3&gt;
&lt;p&gt;Every GitLab project has a &lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;user&#x2F;packages&#x2F;container_registry&#x2F;&quot;&gt;registry&lt;&#x2F;a&gt; at &lt;code&gt;registry.gitlab.com&#x2F;USERNAME&#x2F;PROJECT&lt;&#x2F;code&gt;. This allows me to store, manage, and distribute my &lt;a href=&quot;https:&#x2F;&#x2F;opencontainers.org&#x2F;&quot;&gt;OCI&lt;&#x2F;a&gt; images, alongside the source code and the CI&#x2F;CD pipelines. The authentication from the pipeline to the registry is automatic: GitLab injects &lt;code&gt;CI_REGISTRY_USER&lt;&#x2F;code&gt;, &lt;code&gt;CI_REGISTRY_PASSWORD&lt;&#x2F;code&gt;, &lt;code&gt;CI_REGISTRY&lt;&#x2F;code&gt; environment variables into every pipeline.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;vps-authentication-to-pull-images&quot;&gt;VPS authentication to pull images&lt;&#x2F;h4&gt;
&lt;p&gt;The VPS serving my website need to be able to pull the container image to run it. And for being able to pull the image, it also need to authenticate itself to the container registry. This is where Gitlab deploy token enters the play.&lt;&#x2F;p&gt;
&lt;p&gt;A &lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;user&#x2F;project&#x2F;deploy_tokens&#x2F;&quot;&gt;GitLab deploy token&lt;&#x2F;a&gt; is a non-user specific credential used to authenticate automated tasks, such as &lt;em&gt;a VPS&lt;&#x2F;em&gt;, to access GitLab resources &lt;em&gt;like registries&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I created one GitLab deploy token, I picked the &lt;code&gt;read_registry&lt;&#x2F;code&gt; scope, I stored the credentials in &lt;code&gt;~&#x2F;.config&#x2F;containers&#x2F;auth.json&lt;&#x2F;code&gt;. This file stores your base64 encoded credentials to facilitate future registry operation.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;mlvn@mlvn:~$ cat ~&#x2F;.config&#x2F;containers&#x2F;auth.json
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;auths&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;registry.gitlab.com&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;auth&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;XZwczpnbGR0LUdQeEg2M3pjeWlcGxveS10nskmb2tlbi1tbHZuLo2QnBGeXo1eDR0Z2l0bGFiK2&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;container-registry-cleanup-policy&quot;&gt;Container registry cleanup policy&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;user&#x2F;packages&#x2F;container_registry&#x2F;reduce_container_registry_storage&#x2F;&quot;&gt;Container registries&lt;&#x2F;a&gt; can grow in size if you don&#x27;t manage your registry usage. Retrieving the list of available tags or images becomes slower. Images could take up a large amount of storage space on the server. So I defined a cleanup policy to keep last 5 tags, run weekly, remove tags older than 14 days.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;notification&quot;&gt;Notification mechanism:&lt;&#x2F;h3&gt;
&lt;p&gt;I decided, GitLab CI will SSHes directly into VPS. There was two other options. The first one being a webhook receiver on VPS, which required installing &amp;amp; managing a webhook daemon and opening an extra port. The second one being polling. Why ?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;No extra service to install on VPS&lt;&#x2F;li&gt;
&lt;li&gt;No extra ports to open&lt;&#x2F;li&gt;
&lt;li&gt;Deploy action is visible in GitLab pipeline logs&lt;&#x2F;li&gt;
&lt;li&gt;SSH is already used and understood&lt;&#x2F;li&gt;
&lt;li&gt;No polling delay&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I generated a dedicated ED25519 key pair for GitLab CI, different from my personal key. I stored the private key in GitLab CI variable marked &lt;code&gt;Protected&lt;&#x2F;code&gt; + &lt;code&gt;Masked&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;container-image&quot;&gt;The Container image&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;dockerfile&quot;&gt;The multi-stage Container file&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;dockerfile&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-dockerfile &quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Stage 1: Build static site with Zola
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; docker.io&#x2F;library&#x2F;debian:bookworm-slim &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;AS &lt;&#x2F;span&gt;&lt;span&gt;builder
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;ARG &lt;&#x2F;span&gt;&lt;span&gt;ZOLA_VERSION=0.18.0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;apt-get update &amp;amp;&amp;amp; apt-get install -y --no-install-recommends \
&lt;&#x2F;span&gt;&lt;span&gt;    wget ca-certificates \
&lt;&#x2F;span&gt;&lt;span&gt;    jpegoptim optipng gifsicle libimage-exiftool-perl \
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;amp;&amp;amp; rm -rf &#x2F;var&#x2F;lib&#x2F;apt&#x2F;lists&#x2F;*
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;wget -q &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;https:&#x2F;&#x2F;github.com&#x2F;getzola&#x2F;zola&#x2F;releases&#x2F;download&#x2F;v${ZOLA_VERSION}&#x2F;zola-v${ZOLA_VERSION}-x86_64-unknown-linux-gnu.tar.gz&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; \
&lt;&#x2F;span&gt;&lt;span&gt;    -O &#x2F;tmp&#x2F;zola.tar.gz \
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;amp;&amp;amp; tar -xzf &#x2F;tmp&#x2F;zola.tar.gz -C &#x2F;usr&#x2F;local&#x2F;bin&#x2F; \
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;amp;&amp;amp; chmod +x &#x2F;usr&#x2F;local&#x2F;bin&#x2F;zola \
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;amp;&amp;amp; rm &#x2F;tmp&#x2F;zola.tar.gz
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&lt;span&gt;&#x2F;site
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; config.toml .
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; themes&#x2F; themes&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; static&#x2F; static&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; templates&#x2F; templates&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; content&#x2F; content&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;zola build \
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;amp;&amp;amp; find public -name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;*.xml&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; -o -name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;*.html&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; | xargs sed -i -e &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;\&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;lt;!--.*--&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;\&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;gt;&#x2F;d&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Strip metadata (EXIF, GPS, IPTC, ICC profiles) from all images
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;exiftool -all= -overwrite_original -recurse public
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Optimize images (lossless)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# For lossy JPEG (visually identical, ~60-80% smaller): add --max=85
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;find public -type f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;\(&lt;&#x2F;span&gt;&lt;span&gt; -name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;*.jpg&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; -o -name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;*.jpeg&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;\)&lt;&#x2F;span&gt;&lt;span&gt; -print0 | xargs -0 -r jpegoptim --strip-all \
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;amp;&amp;amp; find public -type f -name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;*.png&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; -print0 | xargs -0 -r optipng -o2 -strip all \
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;amp;&amp;amp; find public -type f -name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;*.gif&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; -print0 | xargs -0 -r gifsicle -O3 --batch
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Stage 2: Serve with minimal Nginx
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; docker.io&#x2F;library&#x2F;nginx:1.25-alpine &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;AS &lt;&#x2F;span&gt;&lt;span&gt;serve
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;RUN &lt;&#x2F;span&gt;&lt;span&gt;rm -rf &#x2F;usr&#x2F;share&#x2F;nginx&#x2F;html&#x2F;*
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; --from=builder &#x2F;site&#x2F;public&#x2F; &#x2F;usr&#x2F;share&#x2F;nginx&#x2F;html&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;COPY&lt;&#x2F;span&gt;&lt;span&gt; nginx.conf &#x2F;etc&#x2F;nginx&#x2F;conf.d&#x2F;default.conf
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;EXPOSE &lt;&#x2F;span&gt;&lt;span&gt;80
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;CMD &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nginx&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-g&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;daemon off;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;nginx-config&quot;&gt;The Nginx configuration file&lt;&#x2F;h3&gt;
&lt;p&gt;Why using Nginx inside the container and not Caddy ? Nginx inside the container serves HTTP only on port 80. SSL is handled by Caddy on the VPS host outside the container. Caddy&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;caddyserver.com&#x2F;features&quot;&gt;killer features&lt;&#x2F;a&gt;, &lt;em&gt;you might want to sit down for this&lt;&#x2F;em&gt;, are completely wasted inside a container that only serves static files over plain HTTP to localhost. &lt;a href=&quot;https:&#x2F;&#x2F;hub.docker.com&#x2F;_&#x2F;nginx&quot;&gt;Nginx Alpine&lt;&#x2F;a&gt; is very small and purpose-built for this job.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;nsukami@IPD-DDSI5:~&#x2F;GIT&#x2F;nskm2$ podman images &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span&gt;grep nginx
&lt;&#x2F;span&gt;&lt;span&gt;docker.io&#x2F;library&#x2F;nginx                                                  1.29.5-alpine-slim  a68d27696acb  3 weeks ago    13.5 MB
&lt;&#x2F;span&gt;&lt;span&gt;docker.io&#x2F;library&#x2F;nginx                                                  1.25-alpine         501d84f5d064  22 months ago  50.1 MB
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;nginx&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-nginx &quot;&gt;&lt;code class=&quot;language-nginx&quot; data-lang=&quot;nginx&quot;&gt;&lt;span&gt;server {
&lt;&#x2F;span&gt;&lt;span&gt;    listen 80;
&lt;&#x2F;span&gt;&lt;span&gt;    root &#x2F;usr&#x2F;share&#x2F;nginx&#x2F;html;
&lt;&#x2F;span&gt;&lt;span&gt;    index index.html;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    gzip on;
&lt;&#x2F;span&gt;&lt;span&gt;    gzip_types text&#x2F;plain text&#x2F;css application&#x2F;json application&#x2F;javascript
&lt;&#x2F;span&gt;&lt;span&gt;               text&#x2F;xml application&#x2F;xml text&#x2F;javascript image&#x2F;svg+xml;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2|webp|mp4|pdf)$ {
&lt;&#x2F;span&gt;&lt;span&gt;        expires 1y;
&lt;&#x2F;span&gt;&lt;span&gt;        add_header Cache-Control &amp;quot;public, immutable&amp;quot;;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    location &#x2F; {
&lt;&#x2F;span&gt;&lt;span&gt;        try_files $uri $uri&#x2F; $uri.html =404;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    error_page 404 &#x2F;404.html;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;vps-provisioning&quot;&gt;The VPS provisioning&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;droplet&quot;&gt;Droplet recommendation&lt;&#x2F;h3&gt;
&lt;p&gt;I am a proud DigitalOcean user since 2011. At that time, I was looking for ways to learn about a real server with a real IP address, the one that are publicly accessible. At that time, I had no credit card, &lt;em&gt;no money to be honest&lt;&#x2F;em&gt;. My first server on this platform was offered to me by a very good friend. He paid for the VPS and gave me the root credentials, then, asked me to correctly harden the server, the rest is history.&lt;&#x2F;p&gt;
&lt;p&gt;For this experiment, 1 vCPU, 1GB RAM, 25GB SSD, Ubuntu 24.04 LTS should be more than enough. Keep the old Droplet running (rsync deploys still work) while you set up the new one, update DNS to the new IP once it&#x27;s ready, then decommission the old one.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;provisioning-steps&quot;&gt;Provisioning steps (in order)&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# 1. Update packages
&lt;&#x2F;span&gt;&lt;span&gt;sudo apt-get update &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;sudo apt-get upgrade -y
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# 2. Firewall
&lt;&#x2F;span&gt;&lt;span&gt;sudo apt-get install -y ufw
&lt;&#x2F;span&gt;&lt;span&gt;sudo ufw allow 1234&#x2F;tcp   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# SSH on custom port
&lt;&#x2F;span&gt;&lt;span&gt;sudo ufw allow 80&#x2F;tcp     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# HTTP (Caddy ACME challenge + redirect)
&lt;&#x2F;span&gt;&lt;span&gt;sudo ufw allow 443&#x2F;tcp    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# HTTPS
&lt;&#x2F;span&gt;&lt;span&gt;sudo ufw enable
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# 3. Install Podman
&lt;&#x2F;span&gt;&lt;span&gt;sudo apt-get -y install podman
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# 4. Install Caddy
&lt;&#x2F;span&gt;&lt;span&gt;sudo apt-get install -y debian-keyring debian-archive-keyring apt-transport-https
&lt;&#x2F;span&gt;&lt;span&gt;curl -1sLf &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;https:&#x2F;&#x2F;dl.cloudsmith.io&#x2F;public&#x2F;caddy&#x2F;stable&#x2F;gpg.key&amp;#39; &lt;&#x2F;span&gt;&lt;span&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span&gt;sudo gpg --dearmor -o &#x2F;usr&#x2F;share&#x2F;keyrings&#x2F;caddy-stable-archive-keyring.gpg
&lt;&#x2F;span&gt;&lt;span&gt;curl -1sLf &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;https:&#x2F;&#x2F;dl.cloudsmith.io&#x2F;public&#x2F;caddy&#x2F;stable&#x2F;debian.deb.txt&amp;#39; &lt;&#x2F;span&gt;&lt;span&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span&gt;sudo tee &#x2F;etc&#x2F;apt&#x2F;sources.list.d&#x2F;caddy-stable.list
&lt;&#x2F;span&gt;&lt;span&gt;sudo apt-get update &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;sudo apt-get install -y caddy
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# 5. Configure Caddy
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# edit &#x2F;etc&#x2F;caddy&#x2F;Caddyfile with the following content:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;#   nskm.xyz {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;#       reverse_proxy localhost:8080
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;#   }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# 6. enable and start the service
&lt;&#x2F;span&gt;&lt;span&gt;sudo systemctl enable caddy &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;sudo systemctl start caddy
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# 7. Authenticate Podman to GitLab registry
&lt;&#x2F;span&gt;&lt;span&gt;podman login registry.gitlab.com -u DEPLOY_TOKEN_USER -p DEPLOY_TOKEN_VALUE
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;vps-hardening&quot;&gt;VPS security hardening&lt;&#x2F;h3&gt;
&lt;p&gt;There are &lt;a href=&quot;https:&#x2F;&#x2F;www.digitalocean.com&#x2F;community&#x2F;tutorials?q=%5Bsecurity%5D+harden&quot;&gt;lots of tutorials&lt;&#x2F;a&gt; explaining how you should harden the security of your server. I think, there is no need to discuss the matter here.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;doctl&quot;&gt;Going further: one-command provisioning with doctl&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.digitalocean.com&#x2F;reference&#x2F;doctl&#x2F;&quot;&gt;doctl&lt;&#x2F;a&gt; is DigitalOcean&#x27;s CLI tool that I&#x27;ve never used. &lt;a href=&quot;https:&#x2F;&#x2F;cloud-init.io&#x2F;&quot;&gt;Cloud-init&lt;&#x2F;a&gt; is a standard way to run scripts on first boot that I&#x27;ve never used too. I absolutely must find a way to use both tools more often.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;A cloud-init script&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It is essentially the provisioning steps from above, packed into a single file that runs automatically when the Droplet first boots. Create a file called &lt;code&gt;cloud-init.sh&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;#cloud-config
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;users&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;mlvn&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;groups&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;shell&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;ALL=(ALL) NOPASSWD:ALL&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;ssh_authorized_keys&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;ssh-ed25519 AAAA... your-public-key-here&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;package_update&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;package_upgrade&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;packages&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;ufw&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;podman&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;fail2ban&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;unattended-upgrades&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;debian-keyring&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;debian-archive-keyring&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;apt-transport-https&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;write_files&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&#x2F;etc&#x2F;caddy&#x2F;Caddyfile&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;content&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      nskm.xyz {
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;          reverse_proxy localhost:8080
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      }
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&#x2F;etc&#x2F;fail2ban&#x2F;jail.d&#x2F;sshd.conf&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;content&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      [sshd]
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      enabled = true
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      port    = 1234
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&#x2F;etc&#x2F;ssh&#x2F;sshd_config.d&#x2F;hardening.conf&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;content&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      PermitRootLogin no
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      PasswordAuthentication no
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      Port 1234
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&#x2F;home&#x2F;mlvn&#x2F;deploy.sh&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;permissions&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;0755&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;owner&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;mlvn:mlvn&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;content&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      #!&#x2F;bin&#x2F;bash
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      set -euo pipefail
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      IMAGE=&amp;quot;registry.gitlab.com&#x2F;USERNAME&#x2F;proj&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      TAG=&amp;quot;${1:-latest}&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      CONTAINER=&amp;quot;nskm-site&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      PORT=8080
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      echo &amp;quot;Deploying ${IMAGE}:${TAG}&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      docker pull &amp;quot;${IMAGE}:${TAG}&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      docker stop &amp;quot;${CONTAINER}&amp;quot; 2&amp;gt;&#x2F;dev&#x2F;null || true
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      docker rm &amp;quot;${CONTAINER}&amp;quot; 2&amp;gt;&#x2F;dev&#x2F;null || true
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      docker run -d --name &amp;quot;${CONTAINER}&amp;quot; --restart unless-stopped -p &amp;quot;${PORT}:80&amp;quot; &amp;quot;${IMAGE}:${TAG}&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      docker image prune -f
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;      echo &amp;quot;Done: ${IMAGE}:${TAG}&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;runcmd&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Firewall
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;ufw allow 1234&#x2F;tcp&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;ufw allow 80&#x2F;tcp&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;ufw allow 443&#x2F;tcp&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;ufw --force enable&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Install Podman
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;apt-get update &amp;amp;&amp;amp; apt-get install -y podman&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Install Caddy
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;curl -1sLf &amp;#39;https:&#x2F;&#x2F;dl.cloudsmith.io&#x2F;public&#x2F;caddy&#x2F;stable&#x2F;gpg.key&amp;#39; | gpg --dearmor -o &#x2F;usr&#x2F;share&#x2F;keyrings&#x2F;caddy-stable-archive-keyring.gpg&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;curl -1sLf &amp;#39;https:&#x2F;&#x2F;dl.cloudsmith.io&#x2F;public&#x2F;caddy&#x2F;stable&#x2F;debian.deb.txt&amp;#39; | tee &#x2F;etc&#x2F;apt&#x2F;sources.list.d&#x2F;caddy-stable.list&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;apt-get update &amp;amp;&amp;amp; apt-get install -y caddy&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;systemctl enable caddy &amp;amp;&amp;amp; systemctl start caddy&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Security
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;systemctl enable fail2ban --now&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;systemctl restart ssh&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;dpkg-reconfigure --priority=low unattended-upgrades&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Enable linger for rootless containers (if using Podman later)
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;loginctl enable-linger mlvn&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Create the Droplet using the doctl command&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;doctl compute droplet create nskm-vps \
&lt;&#x2F;span&gt;&lt;span&gt;  --image ubuntu-24-04-x64 \
&lt;&#x2F;span&gt;&lt;span&gt;  --size s-1vcpu-1gb \
&lt;&#x2F;span&gt;&lt;span&gt;  --region ams3 \
&lt;&#x2F;span&gt;&lt;span&gt;  --ssh-keys $(doctl compute ssh-key list --format ID --no-header &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span&gt;head -1) \
&lt;&#x2F;span&gt;&lt;span&gt;  --user-data-file .&#x2F;cloud-init.sh \
&lt;&#x2F;span&gt;&lt;span&gt;  --wait
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And voilà!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;deploy-script&quot;&gt;Deploy script: &lt;code&gt;&#x2F;home&#x2F;mlvn&#x2F;deploy.sh&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;This is the script that will be called by Gitlab whenever a new image is built:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;#!&#x2F;bin&#x2F;bash
&lt;&#x2F;span&gt;&lt;span&gt;set -euo pipefail
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;IMAGE=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;registry.gitlab.com&#x2F;USERNAME&#x2F;nskm2&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;TAG=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;${&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#dcdcdc;&quot;&gt;1:-&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;latest}&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;CONTAINER=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;nskm-site&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;PORT=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;8080&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;echo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Deploying ${&lt;&#x2F;span&gt;&lt;span&gt;IMAGE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}:${&lt;&#x2F;span&gt;&lt;span&gt;TAG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;docker pull &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;${&lt;&#x2F;span&gt;&lt;span&gt;IMAGE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}:${&lt;&#x2F;span&gt;&lt;span&gt;TAG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;docker stop &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;${&lt;&#x2F;span&gt;&lt;span&gt;CONTAINER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&#x2F;dev&#x2F;null &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|| &lt;&#x2F;span&gt;&lt;span&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;docker rm &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;${&lt;&#x2F;span&gt;&lt;span&gt;CONTAINER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&#x2F;dev&#x2F;null &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|| &lt;&#x2F;span&gt;&lt;span&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;docker run -d --name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;${&lt;&#x2F;span&gt;&lt;span&gt;CONTAINER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; --restart unless-stopped -p &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;${&lt;&#x2F;span&gt;&lt;span&gt;PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}:80&amp;quot; &amp;quot;${&lt;&#x2F;span&gt;&lt;span&gt;IMAGE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}:${&lt;&#x2F;span&gt;&lt;span&gt;TAG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;docker image prune -f
&lt;&#x2F;span&gt;&lt;span&gt;echo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Done: ${&lt;&#x2F;span&gt;&lt;span&gt;IMAGE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}:${&lt;&#x2F;span&gt;&lt;span&gt;TAG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;chmod +x &#x2F;home&#x2F;mlvn&#x2F;deploy.sh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;podman-critical&quot;&gt;Critical: rootless Podman and SSH session lifecycle&lt;&#x2F;h3&gt;
&lt;p&gt;During my various tests, I noticed some strange behaviour. The deploy log shows success and the health check passes, but the site returns 502 immediately after the CI job finishes:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ # Job succeeded....
&lt;&#x2F;span&gt;&lt;span&gt;$ ssh -p 1234 mlvn@$MLVN_IP &amp;quot;&#x2F;home&#x2F;mlvn&#x2F;deploy.sh ${IMAGE_TAG}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;Deploying registry.gitlab.com&#x2F;nskm&#x2F;mlvn:b7fg2abf
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;Running health check...
&lt;&#x2F;span&gt;&lt;span&gt;Done: registry.gitlab.com&#x2F;nskm&#x2F;mlvn:b7fg2abf is live
&lt;&#x2F;span&gt;&lt;span&gt;Job succeeded
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;$ # Yet...
&lt;&#x2F;span&gt;&lt;span&gt;$ curl -I &amp;quot;http:&#x2F;&#x2F;1.2.3.4&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;HTTP&#x2F;1.1 502 Bad Gateway
&lt;&#x2F;span&gt;&lt;span&gt;Server: Caddy
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Even more confusing...&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;podman ps -a&lt;&#x2F;code&gt; shows the container in &lt;code&gt;Exited (0)&lt;&#x2F;code&gt; state, and &lt;code&gt;podman logs nskm-site&lt;&#x2F;code&gt; confirms it received SIGTERM seconds after the health check passed:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;22:03:54 — container starts
&lt;&#x2F;span&gt;&lt;span&gt;22:03:57 — health check hits it: &amp;quot;GET &#x2F; HTTP&#x2F;1.1&amp;quot; 200  ✓
&lt;&#x2F;span&gt;&lt;span&gt;22:04:07 — signal 15 (SIGTERM) received, exiting       ← WTF?!
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;img style=&quot;display: block; margin: 0 auto; width: 300px&quot; src=&quot;&#x2F;images&#x2F;kanye_wtf.gif&quot; alt=&quot;wtf&quot; title=&quot;wtf&quot;&#x2F;&gt;
&lt;br&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;lists.podman.io&#x2F;archives&#x2F;list&#x2F;podman@lists.podman.io&#x2F;thread&#x2F;CQTZAORZXW6UWDNAV5TAWAV6PTDJFW6V&#x2F;&quot;&gt;The problem&lt;&#x2F;a&gt;: When using rootless Podman (Podman running as a regular user, not root), containers are tied to the user&#x27;s login session. When a CI job SSHes into the VPS, runs &lt;code&gt;deploy.sh&lt;&#x2F;code&gt;, and disconnects, the SSH session ends and systemd cleans up the session, sending SIGTERM to all processes in it, including the running container.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.freedesktop.org&#x2F;software&#x2F;systemd&#x2F;man&#x2F;latest&#x2F;loginctl.html&quot;&gt;The solution&lt;&#x2F;a&gt;: enabling lingering for the user running the container:**&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;loginctl enable-linger mlvn  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# run once on the VPS
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This instructs systemd to keep the &lt;code&gt;mlvn&lt;&#x2F;code&gt; user session alive permanently, even after logout. Containers started by this user will survive SSH disconnection.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Verify:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;loginctl show-user mlvn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span&gt;grep Linger
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Expected output: Linger=yes
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;This must be run before the first real deploy.&lt;&#x2F;strong&gt; Without it, every CI deploy will appear to succeed but the site will go down immediately after the SSH session closes.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;ssl-tls&quot;&gt;SSL &amp;amp; Let&#x27;s Encrypt&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;caddy&quot;&gt;Decision: Caddy&lt;&#x2F;h3&gt;
&lt;p&gt;Caddy handles everything automatically with a single config line:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;nskm.xyz {
&lt;&#x2F;span&gt;&lt;span&gt;    reverse_proxy localhost:8080
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In 3 lines, Caddy:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Obtains Let&#x27;s Encrypt cert on first request automatically&lt;&#x2F;li&gt;
&lt;li&gt;Renews before expiry (auto, no cron needed, no certbot)&lt;&#x2F;li&gt;
&lt;li&gt;Redirects HTTP → HTTPS automatically&lt;&#x2F;li&gt;
&lt;li&gt;Stores certs in &lt;code&gt;&#x2F;var&#x2F;lib&#x2F;caddy&#x2F;.local&#x2F;share&#x2F;caddy&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I remember the time when I had to &lt;em&gt;get my geek on&lt;&#x2F;em&gt; and do eveything myself, &lt;em&gt;as a proud Linux user&lt;&#x2F;em&gt;: certbot install, cron job, renewal hooks, manual intervention when things break. &lt;em&gt;Phew&lt;&#x2F;em&gt;!&lt;&#x2F;p&gt;
&lt;img style=&quot;display: block; margin: 0 auto; width: 400px&quot; src=&quot;&#x2F;images&#x2F;jpoesen.png&quot; alt=&quot;A very looooooong time ago&quot; title=&quot;A very looooooong time ago&quot;&#x2F;&gt;
&lt;br&gt;
&lt;h3 id=&quot;letsencrypt-ip&quot;&gt;Let&#x27;s Encrypt IP address certificates (January 2026)&lt;&#x2F;h3&gt;
&lt;p&gt;Amazing how few years ago, it was something you didn&#x27;t think about. Today, Let&#x27;s Encrypt now issues &lt;a href=&quot;https:&#x2F;&#x2F;letsencrypt.org&#x2F;2026&#x2F;01&#x2F;15&#x2F;6day-and-ip-general-availability&quot;&gt;certificates for raw IP addresses&lt;&#x2F;a&gt;. I was thinking about using it for the new VPS, before updating the DNS to the new IP address. Then I learned IP address certs are &lt;a href=&quot;https:&#x2F;&#x2F;letsencrypt.org&#x2F;2026&#x2F;01&#x2F;15&#x2F;6day-and-ip-general-availability&quot;&gt;short-lived certificates&lt;&#x2F;a&gt; — they are valid only for &lt;strong&gt;160 hours (≈6 days)&lt;&#x2F;strong&gt; instead of the usual 90 days. Not a problem in practice, just worth knowing.&lt;&#x2F;p&gt;
&lt;p&gt;Where this could be useful on this VPS ? Maybe ....&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;YOUR_VPS_IP {
&lt;&#x2F;span&gt;&lt;span&gt;    reverse_proxy localhost:SOME_PORT
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;operations&quot;&gt;Operations&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;rollback&quot;&gt;Rollback procedure&lt;&#x2F;h3&gt;
&lt;p&gt;One of the reasons &lt;em&gt;(probably the main reason)&lt;&#x2F;em&gt; I moved to CI&#x2F;CD was the ability to rollback a deployment. With rsync, rolling back meant &quot;do you still have the old files somewhere?&quot;. With container images, every deploy is tagged with its commit SHA and stored in the GitLab registry.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Available image tags on the VPS:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;mlvn@mlvn:~$ podman login registry.gitlab.com
&lt;&#x2F;span&gt;&lt;span&gt;Authenticating with existing credentials for registry.gitlab.com
&lt;&#x2F;span&gt;&lt;span&gt;Existing credentials are valid. Already logged in to registry.gitlab.com
&lt;&#x2F;span&gt;&lt;span&gt;mlvn@mlvn:~$
&lt;&#x2F;span&gt;&lt;span&gt;mlvn@mlvn:~$ podman images --format &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;{{.Repository}}:{{.Tag}}  {{.CreatedAt}}&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span&gt;grep nskm
&lt;&#x2F;span&gt;&lt;span&gt;registry.gitlab.com&#x2F;nskm&#x2F;mlvn:6c08ce72  2026-03-03 06:59:24 +0000 UTC
&lt;&#x2F;span&gt;&lt;span&gt;registry.gitlab.com&#x2F;nskm&#x2F;mlvn:latest  2026-03-01 21:46:30 +0000 UTC
&lt;&#x2F;span&gt;&lt;span&gt;registry.gitlab.com&#x2F;nskm&#x2F;mlvn:b7fb2abf  2026-03-01 21:46:30 +0000 UTC
&lt;&#x2F;span&gt;&lt;span&gt;registry.gitlab.com&#x2F;nskm&#x2F;mlvn:9a326e8c  2026-03-01 21:30:53 +0000 UTC
&lt;&#x2F;span&gt;&lt;span&gt;registry.gitlab.com&#x2F;nskm&#x2F;mlvn:005ba0d9  2026-03-01 17:21:40 +0000 UTC
&lt;&#x2F;span&gt;&lt;span&gt;mlvn@mlvn:~$
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Roll back to a previous version:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;mlvn@mlvn:~$ .&#x2F;deploy.sh b7fb2abf
&lt;&#x2F;span&gt;&lt;span&gt;Login in to the Gitlab container registry
&lt;&#x2F;span&gt;&lt;span&gt;Authenticating with existing credentials for registry.gitlab.com
&lt;&#x2F;span&gt;&lt;span&gt;Existing credentials are valid. Already logged in to registry.gitlab.com
&lt;&#x2F;span&gt;&lt;span&gt;Deploying registry.gitlab.com&#x2F;nskm&#x2F;mlvn:b7fb2abf
&lt;&#x2F;span&gt;&lt;span&gt;Trying to pull registry.gitlab.com&#x2F;nskm&#x2F;mlvn:b7fb2abf...
&lt;&#x2F;span&gt;&lt;span&gt;Getting image source signatures
&lt;&#x2F;span&gt;&lt;span&gt;Copying blob 5406ed7b06d9 skipped: already exists
&lt;&#x2F;span&gt;&lt;span&gt;Copying blob 4abcf2066143 skipped: already exists
&lt;&#x2F;span&gt;&lt;span&gt;Copying blob fc21a1d387f5 skipped: already exists
&lt;&#x2F;span&gt;&lt;span&gt;Copying blob e6ef242c1570 skipped: already exists
&lt;&#x2F;span&gt;&lt;span&gt;Copying blob 13fcfbc94648 skipped: already exists
&lt;&#x2F;span&gt;&lt;span&gt;Copying blob d4bca490e609 skipped: already exists
&lt;&#x2F;span&gt;&lt;span&gt;Copying blob 8a3742a9529d skipped: already exists
&lt;&#x2F;span&gt;&lt;span&gt;Copying blob 0d0c16747d2c skipped: already exists
&lt;&#x2F;span&gt;&lt;span&gt;Copying blob f7809d4c4360 skipped: already exists
&lt;&#x2F;span&gt;&lt;span&gt;Copying blob 3ee6c312ca9b skipped: already exists
&lt;&#x2F;span&gt;&lt;span&gt;Copying blob ed4f6e59d232 skipped: already exists
&lt;&#x2F;span&gt;&lt;span&gt;Copying config 632bfe60dc done   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;Writing manifest to image destination
&lt;&#x2F;span&gt;&lt;span&gt;632bfe60dce5626a87db391496d017ed1dc7d5f805af81fa5936cbb0323c0099
&lt;&#x2F;span&gt;&lt;span&gt;nskm-site
&lt;&#x2F;span&gt;&lt;span&gt;nskm-site
&lt;&#x2F;span&gt;&lt;span&gt;ef7a0a78ee6b047b5fbb0c5b4e6622fff4769096d12ec21384c36149d000f669
&lt;&#x2F;span&gt;&lt;span&gt;Running health check...
&lt;&#x2F;span&gt;&lt;span&gt;Done: registry.gitlab.com&#x2F;nskm&#x2F;mlvn:b7fb2abf is live
&lt;&#x2F;span&gt;&lt;span&gt;mlvn@mlvn:~$
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s it. The deploy script pulls the old image (already cached locally if it was recently used), stops the current container, and starts a new one based on the old image. The site is back to its previous state in seconds.&lt;&#x2F;p&gt;
&lt;p&gt;If the image has been pruned locally, Podman pulls it from the GitLab registry; as long as it&#x27;s within the cleanup policy window.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;image-scanning&quot;&gt;Container image security scanning&lt;&#x2F;h3&gt;
&lt;p&gt;Every container image inherits vulnerabilities from its base image. While &lt;code&gt;debian:bookworm-slim&lt;&#x2F;code&gt; and &lt;code&gt;nginx:1.25-alpine&lt;&#x2F;code&gt; are well-maintained, they still ship with system libraries that occasionally have known CVEs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;trivy.dev&#x2F;&quot;&gt;Trivy&lt;&#x2F;a&gt; is a free, open-source scanner that checks container images against vulnerability databases. Adding it as a CI stage between build and deploy means a vulnerable image never reaches the VPS.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;scan-image&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;stage&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;scan&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;image&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;aquasec&#x2F;trivy:latest&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;entrypoint&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;trivy image&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;--exit-code 1&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;--severity HIGH,CRITICAL&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;--no-progress&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;${IMAGE_NAME}:${IMAGE_TAG}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;needs&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;build-and-push-image&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;rules&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;$CI_COMMIT_BRANCH == &amp;quot;master&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;allow_failure&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;true
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;--exit-code 1&lt;&#x2F;code&gt; makes the pipeline fail if HIGH or CRITICAL vulnerabilities are found. &lt;code&gt;allow_failure: true&lt;&#x2F;code&gt; means the deploy can still proceed — it&#x27;s a warning, not a blocker. Remove &lt;code&gt;allow_failure&lt;&#x2F;code&gt; once you&#x27;re confident in your base images.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;monitoring&quot;&gt;Uptime monitoring&lt;&#x2F;h3&gt;
&lt;p&gt;The CI pipeline can succeed and the site can still go down — I learned that the hard way with the Podman linger issue. The pipeline reports success, you go to bed, and the site has been returning 502 for hours. Nobody notices until someone tries to visit.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;uptimerobot.com&#x2F;&quot;&gt;UptimeRobot&lt;&#x2F;a&gt; pings your site every 5 minutes and notifies you when it&#x27;s unreachable. In this real, there is also &lt;a href=&quot;#&quot;&gt;Hetrix&lt;&#x2F;a&gt;, &lt;a href=&quot;#&quot;&gt;StatusCake&lt;&#x2F;a&gt;, &lt;a href=&quot;#&quot;&gt;Odown&lt;&#x2F;a&gt;, &lt;a href=&quot;#&quot;&gt;Uptime Kuma&lt;&#x2F;a&gt;, &lt;a href=&quot;#&quot;&gt;Better Stack&lt;&#x2F;a&gt;. Never tried none of them.&lt;&#x2F;p&gt;
&lt;p&gt;This is just a way to close the &lt;a href=&quot;https:&#x2F;&#x2F;www.dynatrace.com&#x2F;news&#x2F;blog&#x2F;what-is-observability-2&#x2F;&quot;&gt;observability&lt;&#x2F;a&gt; gap: the CI watches the deploy process, and &lt;em&gt;something&lt;&#x2F;em&gt; watches the &lt;strong&gt;deployed result&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;img style=&quot;display: block; margin: 0 auto; width: 350px&quot; src=&quot;&#x2F;images&#x2F;observability.gif&quot; alt=&quot;observing&quot; title=&quot;Observing&quot;&#x2F;&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;zero-downtime&quot;&gt;Zero-downtime deploys&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;lpalmieri.com&#x2F;posts&#x2F;zero-downtime-deployments&#x2F;&quot;&gt;Zero downtime deployment&lt;&#x2F;a&gt; (ZDD) is the art of updating applications without interrupting service by running &lt;strong&gt;new&lt;&#x2F;strong&gt; and &lt;strong&gt;old&lt;&#x2F;strong&gt; versions simultaneously.&lt;&#x2F;p&gt;
&lt;p&gt;The current deploy script has a brief downtime window: stop old container, start new one. For a personal blog, nobody notices. But it&#x27;s a fun problem to solve and a useful pattern to know.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What I did:&lt;&#x2F;strong&gt; run two containers on two ports (8080 and 8081). Caddy &lt;a href=&quot;https:&#x2F;&#x2F;caddyserver.com&#x2F;docs&#x2F;caddyfile&#x2F;directives&#x2F;reverse_proxy&quot;&gt;reverse proxies&lt;&#x2F;a&gt; to both. At any given time, only one is alive.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Updated Caddyfile:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;nskm.xyz {
&lt;&#x2F;span&gt;&lt;span&gt;    reverse_proxy localhost:8080 localhost:8081
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Caddy with multiple upstreams does &lt;a href=&quot;https:&#x2F;&#x2F;caddyserver.com&#x2F;docs&#x2F;caddyfile&#x2F;directives&#x2F;reverse_proxy#passive-health-checks&quot;&gt;passive health checking&lt;&#x2F;a&gt;, meaning, if one upstream doesn&#x27;t respond, it routes to the other. If a request hits a dead upstream, Caddy retries on the next one before returning an error.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Updated deploy script:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;#!&#x2F;bin&#x2F;bash
&lt;&#x2F;span&gt;&lt;span&gt;set -euo pipefail
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;IMAGE=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;registry.gitlab.com&#x2F;USERNAME&#x2F;proj&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;TAG=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;${&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#dcdcdc;&quot;&gt;1:-&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;latest}&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;podman pull &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;${&lt;&#x2F;span&gt;&lt;span&gt;IMAGE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}:${&lt;&#x2F;span&gt;&lt;span&gt;TAG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Which port is currently in use?
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;podman ps --format &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;{{.Names}}&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span&gt;grep -q &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nskm-site-8080&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;; then
&lt;&#x2F;span&gt;&lt;span&gt;    OLD_PORT=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;8080&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span&gt;NEW_PORT=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;8081&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;else
&lt;&#x2F;span&gt;&lt;span&gt;    OLD_PORT=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;8081&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span&gt;NEW_PORT=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;8080&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;fi
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;echo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Deploying ${&lt;&#x2F;span&gt;&lt;span&gt;IMAGE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}:${&lt;&#x2F;span&gt;&lt;span&gt;TAG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;} on port ${&lt;&#x2F;span&gt;&lt;span&gt;NEW_PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Start new container on the free port
&lt;&#x2F;span&gt;&lt;span&gt;podman run -d --name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nskm-site-${&lt;&#x2F;span&gt;&lt;span&gt;NEW_PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;    --restart unless-stopped -p &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;${&lt;&#x2F;span&gt;&lt;span&gt;NEW_PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}:80&amp;quot; &amp;quot;${&lt;&#x2F;span&gt;&lt;span&gt;IMAGE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}:${&lt;&#x2F;span&gt;&lt;span&gt;TAG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Health check
&lt;&#x2F;span&gt;&lt;span&gt;sleep 2
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if ! &lt;&#x2F;span&gt;&lt;span&gt;curl -sf --max-time 5 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;localhost:${&lt;&#x2F;span&gt;&lt;span&gt;NEW_PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; &#x2F;dev&#x2F;null&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;; then
&lt;&#x2F;span&gt;&lt;span&gt;    echo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Health check FAILED — old container still live on port ${&lt;&#x2F;span&gt;&lt;span&gt;OLD_PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    podman rm -f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nskm-site-${&lt;&#x2F;span&gt;&lt;span&gt;NEW_PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    exit 1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;fi
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Stop old container (Caddy automatically routes to the new one)
&lt;&#x2F;span&gt;&lt;span&gt;podman stop &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nskm-site-${&lt;&#x2F;span&gt;&lt;span&gt;OLD_PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&#x2F;dev&#x2F;null &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|| &lt;&#x2F;span&gt;&lt;span&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;podman rm &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;nskm-site-${&lt;&#x2F;span&gt;&lt;span&gt;OLD_PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&#x2F;dev&#x2F;null &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|| &lt;&#x2F;span&gt;&lt;span&gt;true
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;podman image prune -f
&lt;&#x2F;span&gt;&lt;span&gt;echo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Done: ${&lt;&#x2F;span&gt;&lt;span&gt;IMAGE&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}:${&lt;&#x2F;span&gt;&lt;span&gt;TAG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;} live on port ${&lt;&#x2F;span&gt;&lt;span&gt;NEW_PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;}&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;What happens during a deploy:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;Time ──────────────────────────────────────────────────►
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Old container (:8080)  ████████████████████████████████████▓░░░░░░░░░░
&lt;&#x2F;span&gt;&lt;span&gt;New container (:8081)              ░░░░▓████████████████████████████████
&lt;&#x2F;span&gt;&lt;span&gt;Caddy routes to        ──8080────────────────────────────┐
&lt;&#x2F;span&gt;&lt;span&gt;                                                            └──8081───────
&lt;&#x2F;span&gt;&lt;span&gt;Health check                       ✓
&lt;&#x2F;span&gt;&lt;span&gt;                                          ▲
&lt;&#x2F;span&gt;&lt;span&gt;                                     old stopped here
&lt;&#x2F;span&gt;&lt;span&gt;                                     zero downtime
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Both containers run simultaneously during the transition. Caddy&#x27;s health checking handles the routing. The deploy script only needs to know what is the port Podman is currently running on.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;more&quot;&gt;More on this topic&lt;&#x2F;h2&gt;
&lt;p&gt;The shift from manual rsync deployments to automated CI&#x2F;CD took few hours of research, mistakes, and refinement. The hardest part wasn&#x27;t the Docker setup or GitLab CI — it was that subtle Podman session lifecycle issue that made the site silently disappear after every successful deploy.&lt;&#x2F;p&gt;
&lt;p&gt;But now, deploying is automagic. My site has a full audit trail. I can rollback to any previous version in seconds. And, now that I&#x27;m looking at it, I&#x27;m no longer tethered to one computer.&lt;&#x2F;p&gt;
&lt;p&gt;The trade-offs are real: the pipeline takes longer and there are more moving parts. Yet, I would like to go even further, and make things even funnier: running a Pod inside the VPS, and inside the Pod, having 2 containers, one for the website, and another for, I don&#x27;t know, collect &amp;amp; ship the logs ?! We&#x27;ll see.&lt;&#x2F;p&gt;
&lt;img style=&quot;display: block; margin: 0 auto; width: 350px&quot; src=&quot;&#x2F;images&#x2F;moving_parts.gif&quot; alt=&quot;Too many moving parts&quot; title=&quot;Too many moving parts&quot;&#x2F;&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Here is the big picture showing what has been done:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-text &quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span&gt;+-------------+        git push           +-----------------------------------------+
&lt;&#x2F;span&gt;&lt;span&gt;|             | ------------------------&amp;gt; |                GitLab.com               |
&lt;&#x2F;span&gt;&lt;span&gt;|             |                           |                                         |
&lt;&#x2F;span&gt;&lt;span&gt;|   Laptop    |    email on failure       |                                         |
&lt;&#x2F;span&gt;&lt;span&gt;|             | &amp;lt;------------------------ |  +-----------------------------------+  |
&lt;&#x2F;span&gt;&lt;span&gt;+-------------+                           |  |          CI&#x2F;CD Pipeline           |  |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  |                                   |  |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  |  1. build-and-push-image          |  |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  |     docker build                  |  |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  |     docker push -----------------------------+
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  |                                   |  |       |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  |  2. scan-image (Trivy)            |  |       |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  |     checks for CVEs               |  |       |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  |                                   |  |       |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  |  3. deploy-to-vps                 |  |       |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  |     SSH ---------------------------------+   |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  |                                   |  |   |   |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  +-----------------------------------+  |   |   |
&lt;&#x2F;span&gt;&lt;span&gt;                                          +-----------------------------------------+   |   |
&lt;&#x2F;span&gt;&lt;span&gt;                                                                                        |   |
&lt;&#x2F;span&gt;&lt;span&gt;                                          +--------------------------------------+      |   |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |       GitLab Container Registry      |      |   |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |                                      |      |   |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  IMAGE:abc1234f                      |      |   |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  IMAGE:def5678a                      | &amp;lt;--------+
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  IMAGE:latest                        |      |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |                                      |      |
&lt;&#x2F;span&gt;&lt;span&gt;                                          +-----------------+--------------------+      |
&lt;&#x2F;span&gt;&lt;span&gt;                                                            |                           |
&lt;&#x2F;span&gt;&lt;span&gt;                                                       podman pull                      |
&lt;&#x2F;span&gt;&lt;span&gt;                                                            |                           |
&lt;&#x2F;span&gt;&lt;span&gt;                                                            v                           |
&lt;&#x2F;span&gt;&lt;span&gt;+--------------+    pings every 5 min     +--------------------------------------+      |
&lt;&#x2F;span&gt;&lt;span&gt;|              | ----------------------&amp;gt;  |          DigitalOcean VPS            |      |
&lt;&#x2F;span&gt;&lt;span&gt;|  UptimeRobot |                          |                                      | &amp;lt;----+
&lt;&#x2F;span&gt;&lt;span&gt;|              |  &amp;lt;-- site unreachable    |  +--------+    +------------------+  |
&lt;&#x2F;span&gt;&lt;span&gt;|  alerts via  |                          |  | Caddy  |    | Nginx container  |  |
&lt;&#x2F;span&gt;&lt;span&gt;|  email&#x2F;SMS   |                          |  | :443   +---&amp;gt;| :8080            |  |
&lt;&#x2F;span&gt;&lt;span&gt;+--------------+                          |  |        |    +------------------+  |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  | TLS    |    +------------------+  |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  | HTTPS  +---&amp;gt;| Nginx container  |  |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  |        |    | :8081            |  |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |  +---+----+    +------------------+  |
&lt;&#x2F;span&gt;&lt;span&gt;                                          +------+-------------------------------+
&lt;&#x2F;span&gt;&lt;span&gt;                                                 |
&lt;&#x2F;span&gt;&lt;span&gt;                                            HTTPS :443
&lt;&#x2F;span&gt;&lt;span&gt;                                                 |
&lt;&#x2F;span&gt;&lt;span&gt;                                          +------+-------+
&lt;&#x2F;span&gt;&lt;span&gt;                                          |   Visitor    |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |   Browser    |
&lt;&#x2F;span&gt;&lt;span&gt;                                          +--------------+
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you learned something, please &lt;em&gt;like, share and subscribe&lt;&#x2F;em&gt;. Here are some resources to deepen your understanding:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;devops&#x2F;comments&#x2F;1p8vyxi&#x2F;zero_downtime_deployments_without_kubernetes&#x2F;&quot;&gt;Zero downtime deploymets without K8s&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.podman.io&#x2F;en&#x2F;latest&#x2F;&quot;&gt;What is Podman&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;ci&#x2F;&quot;&gt;GitLab CI&#x2F;CD documentation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=yxNpIL2MqEY&quot;&gt;We use containers now. Here is why&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;certbot.eff.org&#x2F;&quot;&gt;Certbot&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;caddyserver.com&#x2F;docs&#x2F;&quot;&gt;Caddy documentation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=w_lLt4lLplE&quot;&gt;The intro to Docker I wish I had when I started&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.docker.com&#x2F;resources&#x2F;what-is-container-registry&#x2F;&quot;&gt;Container registries 101&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;letsencrypt.org&#x2F;how-it-works&#x2F;&quot;&gt;Let&#x27;s encrypt how it works&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=W3EoZpCr1O8&quot;&gt;Playing with Caddy server&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zola Documentation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;status.gitlab.com&#x2F;&quot;&gt;Gitlab system status&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Vectors</title>
        <published>2026-02-26T00:00:00+00:00</published>
        <updated>2026-02-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/vctrs/"/>
        <id>https://nskm.xyz/posts/vctrs/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/vctrs/">  &lt;img style=&quot;display: block; margin: 0 auto; width: 400px&quot; src=&quot;&#x2F;images&#x2F;vectors.png&quot; alt=&quot;vectors&quot; title=&quot;vectors&quot;&#x2F;&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h2 id=&quot;disclaimers&quot;&gt;Disclaimers :&lt;&#x2F;h2&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Opinions&lt;&#x2F;strong&gt;: The views expressed here are my own unless otherwise specified. They do not represent any employer, organization, or affiliated group.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Code examples&lt;&#x2F;strong&gt;: All code examples are educational. Production use requires careful consideration of performance, security, and your specific data characteristics.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Model choice&lt;&#x2F;strong&gt;: The &lt;code&gt;all-MiniLM-L6-v2&lt;&#x2F;code&gt; model is a practical default, but embedding model selection should depend on your domain. Consider fine-tuning for specialized use cases.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;This article is for&lt;&#x2F;strong&gt;: Django developers curious about semantic search and vector embeddings, or anyone wanting to understand how vectors fit alongside traditional structured data.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;**This article was written on a Framework laptop 16, &lt;em&gt;yeah&lt;&#x2F;em&gt;!
&lt;br&gt;
&lt;br&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;hook&quot;&gt;Hook&lt;&#x2F;h2&gt;
&lt;p&gt;When I start a new &lt;a href=&quot;#&quot;&gt;Django&lt;&#x2F;a&gt; project, the instinct is immediate and familiar: open &lt;code&gt;models.py&lt;&#x2F;code&gt; and start writing &lt;a href=&quot;#&quot;&gt;classes&lt;&#x2F;a&gt;. I think about my entity, its attributes, its relationships, and I translate that mental model almost directly into Python. That&#x27;s great. It works. Since so many years. It&#x27;s readable. It&#x27;s what Django was built for. Amazing. Perfect. Flawless.&lt;&#x2F;p&gt;
&lt;p&gt;If you follow my amazing and colossal work, you know that since more that two years now, I&#x27;m working on a project in the public health sector. I&#x27;m handling lots and lots and lots of data. I have to answer interesting questions like... Yet, I&#x27;m still reprensenting my data using classes and attributes. Reflexes.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s another way to represent data that&#x27;s been quietly powering search engines, recommendation systems, and AI applications for years, it&#x27;s increasingly accessible to application developers like me. I should learn to use it more often. Instead of describing data as a collection of named attributes, I can describe it as a &lt;strong&gt;point in a high-dimensional space&lt;&#x2F;strong&gt;, a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Vector_(mathematics_and_physics)&quot;&gt;vector&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This article walks through what that actually means, when it matters, and how to implement both approaches side by side in a real Django project. To increase your chances of understanding, it is recommended that you listen to this &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=amBBO4PqJKo&quot;&gt;track&lt;&#x2F;a&gt; while reading the article. Enjoy!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;toc&quot;&gt;ToC&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;vctrs&#x2F;#classical-approach&quot;&gt;The classical approach&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;vctrs&#x2F;#vector-approach&quot;&gt;The vector approach&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;vctrs&#x2F;#why-not-ai&quot;&gt;Why this is not just for AI&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;vctrs&#x2F;#both-approaches&quot;&gt;Both approaches in Django&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;vctrs&#x2F;#going-further&quot;&gt;Going further&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;vctrs&#x2F;#broader-landscape&quot;&gt;Representation models&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;vctrs&#x2F;#how-to-practice&quot;&gt;How to practice&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;classical-approach&quot;&gt;The classical approach: data as structure&lt;&#x2F;h2&gt;
&lt;p&gt;When you model a medical facility in a &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;&quot;&gt;surveillance platform&lt;&#x2F;a&gt;, you probably write something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;HealthFacility(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;models.Model&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    name = models.CharField(max_length=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;255&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    region = models.CharField(max_length=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    facility_type = models.CharField(max_length=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;50&lt;&#x2F;span&gt;&lt;span&gt;)  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# hospital, clinic, health_post
&lt;&#x2F;span&gt;&lt;span&gt;    capacity = models.IntegerField()
&lt;&#x2F;span&gt;&lt;span&gt;    services = models.ManyToManyField(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;Service&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is &lt;strong&gt;structured representation&lt;&#x2F;strong&gt;. Data lives in named slots. Querying it means matching those slots exactly:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Find clinics in Dakar with pediatric services
&lt;&#x2F;span&gt;&lt;span&gt;HealthFacility.objects.filter(
&lt;&#x2F;span&gt;&lt;span&gt;    region=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Dakar&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    facility_type=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;clinic&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    services__name=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;pediatrics&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is powerful for what it is. You know exactly what you&#x27;re looking for, the schema enforces consistency, and &lt;a href=&quot;https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;&quot;&gt;SQL&lt;&#x2F;a&gt; is extraordinarily good at these kinds of exact, predicate-based lookups.&lt;&#x2F;p&gt;
&lt;p&gt;The limitation reveals itself the moment your questions become fuzzy. What if you want facilities that are &lt;em&gt;similar&lt;&#x2F;em&gt; to a given one — without being able to define exactly what &quot;similar&quot; means? What if a user types &quot;district hospital with maternal care near the coast&quot; and you need to find the best match? Predicate-based filtering breaks down because similarity isn&#x27;t a predicate. It&#x27;s a geometry problem.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;vector-approach&quot;&gt;The vector approach: data as position&lt;&#x2F;h2&gt;
&lt;p&gt;A vector is simply an ordered list of numbers:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;[0.82, 0.14, 0.67, 0.03, 0.91, ...]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The idea is that you can encode the &lt;em&gt;meaning&lt;&#x2F;em&gt; or &lt;em&gt;characteristics&lt;&#x2F;em&gt; of any piece of data as a point in a high-dimensional space, such that &lt;strong&gt;things which are semantically similar end up close together&lt;&#x2F;strong&gt;, and things that are different end up far apart.&lt;&#x2F;p&gt;
&lt;p&gt;This is not hand-crafted feature engineering &lt;em&gt;(though it can be)&lt;&#x2F;em&gt;. &lt;a href=&quot;https:&#x2F;&#x2F;huggingface.co&#x2F;spaces&#x2F;mteb&#x2F;leaderboard&quot;&gt;Modern embedding models&lt;&#x2F;a&gt; — neural networks trained on massive datasets — can take a sentence, a document, even an image, and produce a dense vector that captures its semantic content. The model has learned, from context, what concepts relate to each other. &quot;Maternal health clinic&quot; and &quot;obstetric care center&quot; will produce vectors that are very close. &quot;Warehouse&quot; will be far away.&lt;&#x2F;p&gt;
&lt;p&gt;The distance between two vectors is typically measured with &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cosine_similarity&quot;&gt;cosine similarity&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;similarity = cos(θ) = (A · B) &#x2F; (||A|| × ||B||)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A value of 1 means identical direction &lt;em&gt;(semantically equivalent)&lt;&#x2F;em&gt;. A value of 0 means orthogonal &lt;em&gt;(unrelated)&lt;&#x2F;em&gt;. This single number replaces the entire predicate matching logic.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;why-not-ai&quot;&gt;Why this is not just for AI projects&lt;&#x2F;h2&gt;
&lt;p&gt;You might think: &quot;I don&#x27;t need semantic search. I need to store patient records.&quot; That&#x27;s fair. This is exactly how I&#x27;ve done it on the &lt;a href=&quot;https:&#x2F;&#x2F;rh.pasteur.sn&#x2F;en&#x2F;research-and-public-health&#x2F;epidemiology-clinical-research-and-data-science&#x2F;fever-surveillance-syndromic-sentinel-surveillance-senegal-4s-network&quot;&gt;4S project&lt;&#x2F;a&gt;. But I&#x27;m more and more facing these new types of scenarios:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Duplicate detection.&lt;&#x2F;strong&gt; Two users register &quot;Hôpital Principal de Dakar&quot; and &quot;hopital principal dakar&quot;. Exact matching fails. Vector similarity catches them as near-duplicates.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Recommendation.&lt;&#x2F;strong&gt; &quot;Users who viewed this report also found these relevant.&quot; You don&#x27;t need a collaborative filtering setup — you can just find the reports whose vectors are closest to the one currently being read.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Free-text search that actually works.&lt;&#x2F;strong&gt; Users don&#x27;t search with your field names. They type natural language. Vectors let you match that intent.... &lt;em&gt;This one stung me very badly recently.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Clustering without labels.&lt;&#x2F;strong&gt; You have 10,000 epidemiological case reports. You want to discover natural groupings without writing filtering rules. Find neighborhoods in vector space.... We are working in this particular topic. I look at how we are implementing this feature and I am already disgusted by the direction we are taking. &lt;em&gt;Marvelous&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Anomaly detection.&lt;&#x2F;strong&gt; A new weekly report has a vector that is very far from all historical ones. Flag it for review.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;both-approaches&quot;&gt;Both approaches in Django: a concrete example&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s build a very small project that models epidemiological reports using both approaches. We&#x27;ll use &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pgvector&#x2F;pgvector&quot;&gt;pgvector&lt;&#x2F;a&gt;, a &lt;a href=&quot;https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;current&#x2F;extend.html&quot;&gt;PostgreSQL extension&lt;&#x2F;a&gt;, so vectors live right next to our traditional Django models. No separate &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Vector_database&quot;&gt;vector databases&lt;&#x2F;a&gt;, no need for new infrastructure if you&#x27;re already on the amazing &lt;a href=&quot;https:&#x2F;&#x2F;www.postgresql.org&#x2F;&quot;&gt;Postgres&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;setup&quot;&gt;Setup&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;pip install django pgvector sentence-transformers psycopg2-binary  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# easy peasy
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Enable the extension in a Django migration:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;pgvector.django &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;VectorExtension
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Migration(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;migrations.Migration&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    operations = [
&lt;&#x2F;span&gt;&lt;span&gt;        VectorExtension(),
&lt;&#x2F;span&gt;&lt;span&gt;    ]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;the-traditional-model&quot;&gt;The traditional model&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# surveillance&#x2F;models.py
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.db &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;models
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;pgvector.django &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;VectorField
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;EpiReport(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;models.Model&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    Classical structured representation.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    Every piece of information lives in a named, typed field.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    title = models.CharField(max_length=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;255&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    region = models.CharField(max_length=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    disease = models.CharField(max_length=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    week = models.IntegerField()
&lt;&#x2F;span&gt;&lt;span&gt;    year = models.IntegerField()
&lt;&#x2F;span&gt;&lt;span&gt;    case_count = models.IntegerField(default=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    severity = models.CharField(
&lt;&#x2F;span&gt;&lt;span&gt;        max_length=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        choices=[(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;low&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Low&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;), (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;moderate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Moderate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;), (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;high&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;High&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)]
&lt;&#x2F;span&gt;&lt;span&gt;    )
&lt;&#x2F;span&gt;&lt;span&gt;    summary = models.TextField()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# The vector representation lives alongside the structured one.
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# 384 dimensions is the output size of the model we&amp;#39;ll use.
&lt;&#x2F;span&gt;&lt;span&gt;    embedding = VectorField(dimensions=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;384&lt;&#x2F;span&gt;&lt;span&gt;, null=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;, blank=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Meta:
&lt;&#x2F;span&gt;&lt;span&gt;        indexes = [
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Traditional index for structured queries
&lt;&#x2F;span&gt;&lt;span&gt;            models.Index(fields=[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;region&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;disease&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;year&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]),
&lt;&#x2F;span&gt;&lt;span&gt;        ]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;__str__(self):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;{self.title}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;{self.region}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;, W&lt;&#x2F;span&gt;&lt;span&gt;{self.week}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;{self.year}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;)&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that both representations coexist in the same table. This is intentional — we&#x27;re not replacing one with the other. We&#x27;re giving ourselves two different query interfaces into the same data.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;generating-the-embedding&quot;&gt;Generating the embedding&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# surveillance&#x2F;embeddings.py
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;sentence_transformers &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;SentenceTransformer
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# All-MiniLM-L6-v2 is small (80MB), fast, and produces 384-dim vectors.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# It runs on CPU without issue, which matters in resource-constrained environments.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# See here: https:&#x2F;&#x2F;huggingface.co&#x2F;sentence-transformers&#x2F;all-MiniLM-L6-v2
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;_model = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;get_model():
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;global &lt;&#x2F;span&gt;&lt;span&gt;_model
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;_model &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;is None&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        _model = SentenceTransformer(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;all-MiniLM-L6-v2&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;_model
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;embed_report(report: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;EpiReport&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; list[float]:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    Convert a report&amp;#39;s semantic content into a vector.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    The text we embed is a natural language description of the report,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    so the model can capture the meaning, not just the keywords.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    text = (
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;{report.title}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;. &amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Disease: &lt;&#x2F;span&gt;&lt;span&gt;{report.disease}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;. &amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Region: &lt;&#x2F;span&gt;&lt;span&gt;{report.region}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;. &amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Severity: &lt;&#x2F;span&gt;&lt;span&gt;{report.severity}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;. &amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;{report.summary}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    )
&lt;&#x2F;span&gt;&lt;span&gt;    model = get_model()
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;model.encode(text).tolist()
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;the-two-query-styles-side-by-side&quot;&gt;The two query styles, side by side&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# surveillance&#x2F;queries.py
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;pgvector.django &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;CosineDistance
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from .&lt;&#x2F;span&gt;&lt;span&gt;models &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;EpiReport
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from .&lt;&#x2F;span&gt;&lt;span&gt;embeddings &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;get_model
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# ── Approach 1: Structured Query ────────────────────────────────────────────
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;get_high_severity_reports(region: str, disease: str, year: int):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    Classical Django ORM query.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    Fast, precise, requires you to know exactly what you want.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;EpiReport.objects.filter(
&lt;&#x2F;span&gt;&lt;span&gt;        region=region,
&lt;&#x2F;span&gt;&lt;span&gt;        disease=disease,
&lt;&#x2F;span&gt;&lt;span&gt;        year=year,
&lt;&#x2F;span&gt;&lt;span&gt;        severity=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;high&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    ).order_by(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-week&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# ── Approach 2: Semantic Vector Query ───────────────────────────────────────
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;find_similar_reports(query: str, top_k: int = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    Vector similarity search.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    The query is natural language. No schema knowledge required.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    Returns the most semantically similar reports.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    model = get_model()
&lt;&#x2F;span&gt;&lt;span&gt;    query_vector = model.encode(query).tolist()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        EpiReport.objects
&lt;&#x2F;span&gt;&lt;span&gt;        .annotate(distance=CosineDistance(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;embedding&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, query_vector))
&lt;&#x2F;span&gt;&lt;span&gt;        .order_by(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;distance&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)[:top_k]
&lt;&#x2F;span&gt;&lt;span&gt;    )
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;find_similar_to_report(report: EpiReport, top_k: int = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    Given an existing report, find others that are semantically similar.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    Useful for &amp;quot;related reports&amp;quot; features or duplicate detection.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        EpiReport.objects
&lt;&#x2F;span&gt;&lt;span&gt;        .exclude(pk=report.pk)
&lt;&#x2F;span&gt;&lt;span&gt;        .annotate(distance=CosineDistance(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;embedding&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, report.embedding))
&lt;&#x2F;span&gt;&lt;span&gt;        .order_by(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;distance&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)[:top_k]
&lt;&#x2F;span&gt;&lt;span&gt;    )
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;wiring-it-into-views&quot;&gt;Wiring it into views&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# surveillance&#x2F;views.py
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.http &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;JsonResponse
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from .&lt;&#x2F;span&gt;&lt;span&gt;models &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;EpiReport
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from .&lt;&#x2F;span&gt;&lt;span&gt;queries &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;get_high_severity_reports, find_similar_reports
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;structured_search(request):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;Traditional form-based search.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    reports = get_high_severity_reports(
&lt;&#x2F;span&gt;&lt;span&gt;        region=request.GET.get(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;region&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;        disease=request.GET.get(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;disease&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;        year=int(request.GET.get(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;year&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2024&lt;&#x2F;span&gt;&lt;span&gt;)),
&lt;&#x2F;span&gt;&lt;span&gt;    )
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;JsonResponse({
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;approach&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;structured&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;results&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: list(reports.values(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;title&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;region&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;disease&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;severity&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;    })
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;semantic_search(request):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;Free-text semantic search.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    query = request.GET.get(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;q&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    reports = find_similar_reports(query, top_k=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;JsonResponse({
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;approach&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;vector&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;query&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: query,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;results&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [
&lt;&#x2F;span&gt;&lt;span&gt;            {
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;title&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: r.title,
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;region&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: r.region,
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;disease&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: r.disease,
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;similarity&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: round(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span&gt;- r.distance, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;),  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# convert distance to similarity
&lt;&#x2F;span&gt;&lt;span&gt;            }
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;r &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;reports
&lt;&#x2F;span&gt;&lt;span&gt;        ]
&lt;&#x2F;span&gt;&lt;span&gt;    })
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now try these two requests:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;GET &#x2F;search&#x2F;structured&#x2F;?region=Dakar&amp;amp;disease=cholera&amp;amp;year=2024
&lt;&#x2F;span&gt;&lt;span&gt;GET &#x2F;search&#x2F;semantic&#x2F;?q=waterborne disease outbreaks in coastal areas
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The structured search finds exactly what you specified. The semantic search finds what you &lt;em&gt;meant&lt;&#x2F;em&gt;, even if those exact words don&#x27;t appear anywhere in your data. The world is beautiful.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;when-to-use&quot;&gt;When to use which&lt;&#x2F;h2&gt;
&lt;p&gt;On top of my tiny experience, and as a software engineer who has never used this technique on &lt;em&gt;on production&lt;&#x2F;em&gt;, I would say the right answer for most systems is both. And pgvector makes that even more practical without adding infrastructure complexity.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Lean on structured queries&lt;&#x2F;strong&gt; when you need exactness: filtering by date range, counting cases, producing regulatory reports, joining across tables. SQL is unbeatable here.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Lean on vector queries&lt;&#x2F;strong&gt; when you need semantic understanding: search boxes, recommendation engines, duplicate detection, anomaly flagging, clustering, or any time a user&#x27;s intent can&#x27;t be reduced to a dropdown value.&lt;&#x2F;p&gt;
&lt;p&gt;Even more interesting, &lt;strong&gt;hybrid search&lt;&#x2F;strong&gt;: use structured filters to narrow the candidate set, then rank the survivors by vector similarity:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;hybrid_search(region: str, query: str, top_k: int = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    Filter structurally, then rank semantically.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    This is typically the most useful approach in production.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    model = get_model()
&lt;&#x2F;span&gt;&lt;span&gt;    query_vector = model.encode(query).tolist()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        EpiReport.objects
&lt;&#x2F;span&gt;&lt;span&gt;        .filter(region=region)  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# hard filter: only this region
&lt;&#x2F;span&gt;&lt;span&gt;        .annotate(distance=CosineDistance(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;embedding&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, query_vector))
&lt;&#x2F;span&gt;&lt;span&gt;        .order_by(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;distance&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)[:top_k]
&lt;&#x2F;span&gt;&lt;span&gt;    )
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;going-further&quot;&gt;Going further&lt;&#x2F;h2&gt;
&lt;p&gt;Once you&#x27;ve internalized the two-lens model, here&#x27;s where to take it next:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-fine-tune-your-own-embedding-model-on-domain-data&quot;&gt;1. Fine-tune your own embedding model on domain data&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;all-MiniLM-L6-v2&lt;&#x2F;code&gt; &lt;a href=&quot;https:&#x2F;&#x2F;www.sbert.net&#x2F;&quot;&gt;model&lt;&#x2F;a&gt; was trained on general English text. It has no idea that &quot;paludisme&quot; and &quot;malaria&quot; are the same thing, or that &quot;cas suspects&quot; and &quot;suspected cases&quot; are equivalent in my context. Training a domain-specific embedding model on my own epidemiological corpus — even with a small dataset using contrastive learning — would make similarity search dramatically more meaningful.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-retrieval-augmented-generation-rag-on-top-of-our-vector-store&quot;&gt;2. Retrieval-augmented generation (RAG) on top of our vector store&lt;&#x2F;h3&gt;
&lt;p&gt;Once we have a vector store of reports, we&#x27;re one step away from a system that can &lt;em&gt;answer questions&lt;&#x2F;em&gt; about your data in natural language. A user asks: &lt;em&gt;&quot;What were the major respiratory disease trends in Guinea-Bissau in 2023?&quot;&lt;&#x2F;em&gt; — our system retrieves the most relevant reports by vector similarity, then feeds them as context to an &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Large_language_model&quot;&gt;LLM&lt;&#x2F;a&gt; that synthesizes a coherent answer.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-vectors-for-anomaly-detection-in-surveillance-data&quot;&gt;3. Vectors for anomaly detection in surveillance data&lt;&#x2F;h3&gt;
&lt;p&gt;Every week a new batch of case reports comes in. &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#engineers&quot;&gt;We&lt;&#x2F;a&gt; can embed each report and compare it to the historical distribution of vectors for that region and disease. A report that lands far from the cluster is a statistical anomaly, potentially a real &lt;a href=&quot;https:&#x2F;&#x2F;www.who.int&#x2F;activities&#x2F;epidemic-and-pandemic-monitoring&quot;&gt;outbreak signal&lt;&#x2F;a&gt;. This turns our vector store into a passive early-warning system without writing any explicit outbreak-detection rules.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4-multimodal-embeddings&quot;&gt;4. Multimodal embeddings&lt;&#x2F;h3&gt;
&lt;p&gt;Text isn&#x27;t the only thing we can embed. We can embed laboratory results, genomic sequences, geographic coordinates combined with case counts, even scanned paper forms via vision models. The moment we have multiple modalities in the same vector space, we can do cross-modal search: &lt;em&gt;find reports whose geographic spread pattern resembles this map image.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;placeholder image for brain explosion&lt;&#x2F;p&gt;
&lt;h3 id=&quot;5-the-theory-underneath-why-vector-spaces-work&quot;&gt;5. The theory underneath: why vector spaces work&lt;&#x2F;h3&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;broader-landscape&quot;&gt;Representation models: other ways to represent data&lt;&#x2F;h2&gt;
&lt;p&gt;Structured attributes and vectors are two lenses. And there are other ways to represent data:&lt;&#x2F;p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot;&gt;
  &lt;tr style=&quot;border: 1px solid #ddd;&quot;&gt;
    &lt;th style=&quot;border: 1px solid #ddd; padding: 12px; text-align: left;&quot;&gt;Representation&lt;&#x2F;th&gt;
    &lt;th style=&quot;border: 1px solid #ddd; padding: 12px; text-align: left;&quot;&gt;Best question it answers&lt;&#x2F;th&gt;
    &lt;th style=&quot;border: 1px solid #ddd; padding: 12px; text-align: left;&quot;&gt;Tools&lt;&#x2F;th&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr style=&quot;border: 1px solid #ddd;&quot;&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;Class + attributes&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;What does this thing have?&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;Django ORM, PostgreSQL&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr style=&quot;border: 1px solid #ddd;&quot;&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;Vector&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;What is this thing like?&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;pgvector, sentence-transformers&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr style=&quot;border: 1px solid #ddd;&quot;&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;Graph&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;How does this thing connect?&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;Neo4j, networkx&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr style=&quot;border: 1px solid #ddd;&quot;&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;Event stream&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;How did this thing become what it is?&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;Kafka, EventStoreDB&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr style=&quot;border: 1px solid #ddd;&quot;&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;Logic &#x2F; facts&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;What can we conclude about this thing?&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;Prolog, Datalog, RDF&#x2F;OWL&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr style=&quot;border: 1px solid #ddd;&quot;&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;Probability&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;How certain are we about this thing?&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;PyMC, Stan&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr style=&quot;border: 1px solid #ddd;&quot;&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;Spatial&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;Where is this thing, relative to what?&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;PostGIS, GeoDjango&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr style=&quot;border: 1px solid #ddd;&quot;&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;Tensor&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;How does this vary across multiple dimensions?&lt;&#x2F;td&gt;
    &lt;td style=&quot;border: 1px solid #ddd; padding: 12px;&quot;&gt;NumPy, PyTorch, Xarray&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
&lt;&#x2F;table&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;how-to-practice&quot;&gt;How to practice&lt;&#x2F;h2&gt;
&lt;p&gt;You don&#x27;t need production data to start experimenting with vectors and embeddings:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Local development:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.trychroma.com&#x2F;&quot;&gt;Chroma&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Lightweight vector database that runs locally or in Docker.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;hub.docker.com&#x2F;r&#x2F;pgvector&#x2F;pgvector&quot;&gt;pgvector in Docker&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: A local PostgreSQL with pgvector extension in seconds.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.sbert.net&#x2F;docs&#x2F;pretrained_models.html&quot;&gt;Sentence Transformers Models&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Experiment with domain-specific models beyond all-MiniLM-L6-v2.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Learning resources:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;huggingface.co&#x2F;models&quot;&gt;Hugging Face Hub&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: 100k+ pre-trained models. Read papers, compare benchmark results.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;huggingface.co&#x2F;learn&quot;&gt;Embedding Models Course&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Free, practical introduction to embeddings.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pgvector&#x2F;pgvector&quot;&gt;pgvector Documentation&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: All indexing strategies and similarity operators explained.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;more-on-this-topic&quot;&gt;More on this topic&lt;&#x2F;h2&gt;
&lt;p&gt;As a Django engineer, my mental model of &quot;data as class with attributes&quot; is solid and won&#x27;t stop serving &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;images&#x2F;Nsukami_Patrick.pdf&quot;&gt;me&lt;&#x2F;a&gt;. But it&#x27;s worth internalizing that it&#x27;s one of at least two valid representations. I should definitely start to think of my data as having a &lt;em&gt;position&lt;&#x2F;em&gt; in semantic space, a whole class of problems (search, similarity, anomaly, clustering) will become natural rather than bespoke.&lt;&#x2F;p&gt;
&lt;p&gt;Here we are, we wanted a banana but we received a gorilla holding the banana and the entire jungle. Here are some links to help you &lt;em&gt;(and me, let&#x27;s be honest)&lt;&#x2F;em&gt; go further and tame the beast:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;dev.to&#x2F;dev_kiran&#x2F;embeddings-the-hidden-power-behind-ai-search-21eb&quot;&gt;The hidden power behind AI &amp;amp; search&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.sbert.net&#x2F;docs&#x2F;training&#x2F;overview.html&quot;&gt;Fine-tuning sentence transformers&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;vickiboykis.com&#x2F;what_are_embeddings&#x2F;&quot;&gt;Vector database comparison&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;lilianweng.github.io&#x2F;posts&#x2F;2021-05-31-contrastive&#x2F;&quot;&gt;Contrastive learning explained&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;2005.11401&quot;&gt;Retrieval-Augmented Generation (RAG)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pgvector&#x2F;pgvector#performance&quot;&gt;pgvector performance tuning&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.cs.utexas.edu&#x2F;~EWD&#x2F;transcriptions&#x2F;EWD06xx&#x2F;EWD667.html&quot;&gt;On the foolishness of &quot;natural language programming&quot;&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you found this article useful, &lt;em&gt;please like, share and subscribe&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;while-i-still-have-your-attention&quot;&gt;While I still have your attention&lt;&#x2F;h2&gt;
&lt;p&gt;The Norwegian Consumer Council is an independent, governmentally funded organisation that advocates for consumer’s rights. It should be easy for consumers to make sustainable choices every day. Consumers have the right to be protected against exploitation – both financially and digitally. To ensure this, we work to provide easy access to information, enforceable rights, and sufficient redress options when something goes wrong.&lt;&#x2F;p&gt;
&lt;p&gt;Digital products and services keep getting worse. In the new report Breaking Free: Pathways to a fair technological future, the Norwegian Consumer Council has delved into &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=T4Upf_B9RLQ&quot;&gt;enshittification&lt;&#x2F;a&gt; and how to resist it. The report shows how this phenomenon affects both consumers and society at large, but that it is possible to &lt;a href=&quot;https:&#x2F;&#x2F;www.forbrukerradet.no&#x2F;breakingfree&quot;&gt;turn the tide.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Geez&lt;&#x2F;em&gt;, I would have loved to see African leaders do the same....&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>AWS (Day 1)</title>
        <published>2026-02-02T00:00:00+00:00</published>
        <updated>2026-02-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/aws-1/"/>
        <id>https://nskm.xyz/posts/aws-1/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/aws-1/">  &lt;img style=&quot;display: block; margin: 0 auto; width: 400px&quot; src=&quot;&#x2F;images&#x2F;cloud-infra.jpg&quot; alt=&quot;infrastructure&quot; title=&quot;infrastructure&quot;&#x2F;&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h2 id=&quot;disclaimers&quot;&gt;Disclaimers :&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Opinions expressed in this post &lt;em&gt;(and in any of all my posts)&lt;&#x2F;em&gt; are solely, &lt;em&gt;unless otherwise specified&lt;&#x2F;em&gt;, those of the authors, &lt;em&gt;me&lt;&#x2F;em&gt;. Those opinions absolutely do not reflect the views, policies, positions of any organizations, employers, affiliated groups.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I don&#x27;t agree with this, but my employer says I don&#x27;t have the right to share the source code I&#x27;ve written in the course of my work. &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;shorts&#x2F;FEYlE8pHICk&quot;&gt;I don&#x27;t ever want a problem&lt;&#x2F;a&gt;. So, I&#x27;ll try to say as much as I can without divulging any specific information.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Writing acts as a powerful therapeutic outlet, allowing emotions such as anger and irritation to be released.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;If you are a colleague and recognize the situation described below, remember: I&#x27;m critiquing the system, not the people.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Just in case my honesty lands me in hot water, my resume is &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;images&#x2F;Nsukami_Patrick.pdf&quot;&gt;here&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;This article is written primarily for Tidiane and Dethie.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I&#x27;ve strived for accuracy throughout this piece, but if you catch any errors, please reach out—I&#x27;d be grateful for the feedback and happy to make updates!&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Render unto Caesar what is Caesar&#x27;s, Claude helped me find up-to-date documentation links and he also helped beautify all the diagrams used (and not used) in this article.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h2 id=&quot;hook&quot;&gt;Hook&lt;&#x2F;h2&gt;
&lt;p&gt;One of the joys of corporate life: you&#x27;re politely asked what training would help you be more productive, and a few months later, you&#x27;re enrolled in something completely unrelated to your request.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve been asked to take a course called &quot;AWS Automation and Observability.&quot; Of course, I only have one choice: accept. Even though I don&#x27;t need it. Even though I find it thoroughly boring. Even though I consider the whole thing unnecessary.&lt;&#x2F;p&gt;
&lt;p&gt;Being forced into training you didn&#x27;t choose &lt;em&gt;(especially when you already have solid technical skills)&lt;&#x2F;em&gt; is frustrating. It&#x27;s even more frustrating when the content feels dated; someone in 2026 teaching &lt;a href=&quot;https:&#x2F;&#x2F;i.giphy.com&#x2F;pPhyAv5t9V8djyRFJH.webp&quot;&gt;Jenkins&lt;&#x2F;a&gt; as if it&#x27;s revolutionary feels like being taught to use a rotary phone.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s a certain irony in being told:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;« Il est strictement interdit d&#x27;enregistrer, de filmer ou de fixer par quelque moyen que ce soit les sessions de formation. Les supports doivent rester confidentiels. »&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;...when the material itself is widely available online and hardly groundbreaking, when &lt;em&gt;(at least for day 0)&lt;&#x2F;em&gt;, there was no custom material given by the instructor. I respect the instructor&#x27;s knowledge of the subject, &lt;em&gt;he clearly knows his stuff&lt;&#x2F;em&gt;, but the format, the delivery, and the relevance left much to be desired.&lt;&#x2F;p&gt;
&lt;p&gt;Perhaps the problem isn&#x27;t the instructor but the constraints he was working under: limited time, the fact that there were too many people with different levels in the same class or budget restrictions. Still, mandatory training should be engaging, current, and actually useful. This was none of those things.&lt;&#x2F;p&gt;
&lt;p&gt;Since there&#x27;s no escaping it, might as well make the most of it and stay in a &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=m7XZyj6Ru9w&quot;&gt;good mood&lt;&#x2F;a&gt;. Let&#x27;s talk about what I wish the first day had covered and &lt;em&gt;how&lt;&#x2F;em&gt; it should have been covered.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aws&quot;&gt;AWS&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;intro&quot;&gt;Intro&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;&quot;&gt;Amazon Web Services (AWS)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; is Amazon&#x27;s cloud computing platform, launched in 2006 with two initial services: &lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;s3&#x2F;&quot;&gt;S3 (Simple Storage Service)&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;ec2&#x2F;&quot;&gt;EC2 (Elastic Compute Cloud)&lt;&#x2F;a&gt;. The idea emerged from Amazon&#x27;s internal infrastructure challenges—they had built robust, scalable systems to handle their e-commerce peaks, and realized they could rent that infrastructure to others.&lt;&#x2F;p&gt;
&lt;p&gt;Today, AWS offers &lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;products&#x2F;&quot;&gt;200+ services&lt;&#x2F;a&gt; spanning compute, storage, databases, machine learning, networking, and more. It holds roughly 31% of the global cloud market share (as of 2024), making it the largest cloud provider. &lt;em&gt;Phew&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In Africa, the &lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;local&#x2F;africa&#x2F;cape-town&#x2F;&quot;&gt;Cape Town region (af-south-1)&lt;&#x2F;a&gt; was launched in 2020. It is AWS&#x27;s first and currently only African region. There&#x27;s no dedicated region yet for West Africa specifically. Users typically connect to eu-west-3 (Paris) or af-south-1 (Cape Town) depending on latency requirements.&lt;&#x2F;p&gt;
&lt;p&gt;AWS does also have :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;about-aws&#x2F;whats-new&#x2F;2023&#x2F;06&#x2F;aws-edge-location-nigeria&#x2F;&quot;&gt;Edge locations (CloudFront POPs) in Lagos and Nairobi&lt;&#x2F;a&gt; for content delivery.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;about-aws&#x2F;whats-new&#x2F;2025&#x2F;04&#x2F;aws-wavelength-zone-dakar&#x2F;&quot;&gt;Wavelength zone in Dakar Senegal&lt;&#x2F;a&gt;, a new type of infrastructure designed to run workloads that require low latency or edge resiliency.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;alternatives-the-hyperscalers&quot;&gt;Alternatives: the hyperscalers&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Hyperscalers&lt;&#x2F;strong&gt; are cloud providers operating at &lt;em&gt;massive&lt;&#x2F;em&gt; scale; we are talking about data centers across multiple continents, serving &lt;em&gt;millionZ&lt;&#x2F;em&gt; of customers simultaneously. The &lt;em&gt;&quot;Big 3&quot;&lt;&#x2F;em&gt; dominate the market:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Provider &lt;&#x2F;th&gt;&lt;th&gt;Share&lt;&#x2F;th&gt;&lt;th&gt;Strengths&lt;&#x2F;th&gt;&lt;th&gt;Best For&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;&quot;&gt;AWS&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;~31%&lt;&#x2F;td&gt;&lt;td&gt;Widest service catalog, mature ecosystem&lt;&#x2F;td&gt;&lt;td&gt;General purpose, enterprise, startups&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;azure.microsoft.com&#x2F;&quot;&gt;Azure&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;~24%&lt;&#x2F;td&gt;&lt;td&gt;Windows integration, hybrid cloud&lt;&#x2F;td&gt;&lt;td&gt;Microsoft shops, hybrid deployments&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;cloud.google.com&#x2F;&quot;&gt;GCP&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;~11%&lt;&#x2F;td&gt;&lt;td&gt;Data analytics, ML&#x2F;AI (TensorFlow), Kubernetes &lt;&#x2F;td&gt;&lt;td&gt;Data-heavy workloads, ML projects&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;Notable alternatives:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.digitalocean.com&#x2F;&quot;&gt;DigitalOcean&lt;&#x2F;a&gt; &#x2F; &lt;a href=&quot;https:&#x2F;&#x2F;www.linode.com&#x2F;&quot;&gt;Linode&lt;&#x2F;a&gt; &#x2F; &lt;a href=&quot;https:&#x2F;&#x2F;www.vultr.com&#x2F;&quot;&gt;Vultr&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; — Simpler, developer-friendly, cheaper for small workloads&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.ovhcloud.com&#x2F;&quot;&gt;OVHcloud&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; — European provider, good for GDPR compliance, competitive pricing&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.scaleway.com&#x2F;&quot;&gt;Scaleway&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; — French provider, strong EU presence, interesting ARM offerings&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.hetzner.com&#x2F;&quot;&gt;Hetzner&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; — German provider, excellent price-to-performance ratio, popular for self-hosted projects&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The hyperscaler choice often comes down to existing tooling, team expertise, and specific service needs rather than raw capability. They all solve similar problems.&lt;&#x2F;p&gt;
&lt;p&gt;As an advocate for the &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;philosophy&#x2F;free-software-intro.en.html&quot;&gt;free software movement&lt;&#x2F;a&gt;, what is my advice ?&lt;&#x2F;p&gt;
&lt;p&gt;GCP: Although proprietary &lt;em&gt;&amp;amp; evil&lt;&#x2F;em&gt;, I should admit, Google has historically &lt;a href=&quot;https:&#x2F;&#x2F;opensource.google&#x2F;projects&quot;&gt;opened up key technologies&lt;&#x2F;a&gt; such as Kubernetes and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google&quot;&gt;many others&lt;&#x2F;a&gt; to promote interoperability and encourage customers to leave more closed competitors.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.redhat.com&#x2F;en&#x2F;technologies&#x2F;cloud-computing&#x2F;openshift&quot;&gt;Red Hat OpenShift (on any cloud)&lt;&#x2F;a&gt;: Not a &lt;a href=&quot;https:&#x2F;&#x2F;www.redhat.com&#x2F;en&#x2F;topics&#x2F;cloud-computing&#x2F;what-is-a-hyperscaler&quot;&gt;hyperscaler&lt;&#x2F;a&gt; per se, but using this platform on a cloud infrastructure allows you to maintain a free and portable software layer between different providers.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;why-would-a-biomedical-research-center-use-aws&quot;&gt;Why would a biomedical research center use AWS ?&lt;&#x2F;h3&gt;
&lt;p&gt;For an organization handling sensitive health data and research workloads:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Compliance&lt;&#x2F;strong&gt;: HIPAA, GDPR-ready configurations&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Burst capacity&lt;&#x2F;strong&gt;: spin up hundreds of CPUs for genomic analysis, pay only for what you use&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Global collaboration&lt;&#x2F;strong&gt;: share datasets across continents with proper access controls&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Focus on research&lt;&#x2F;strong&gt;: less time managing servers, more time on science&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of contents&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;aws-1&#x2F;#fundamentals&quot;&gt;Fundamentals&lt;&#x2F;a&gt; - Where things are (Regions, Availability Zones, Organizations)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;aws-1&#x2F;#identity-and-access-management&quot;&gt;Identity and Access Management&lt;&#x2F;a&gt; - Who can do what (IAM)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;aws-1&#x2F;#network&quot;&gt;Network&lt;&#x2F;a&gt; - How things connect
&lt;ul&gt;
&lt;li&gt;VPC basics (CIDR, Subnets)&lt;&#x2F;li&gt;
&lt;li&gt;Gateways (IGW, NAT)&lt;&#x2F;li&gt;
&lt;li&gt;Hybrid connectivity (VPN, Direct Connect)&lt;&#x2F;li&gt;
&lt;li&gt;Network Security (Security Groups, NACLs)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;aws-1&#x2F;#load-balancing&quot;&gt;Load Balancing&lt;&#x2F;a&gt; - Traffic distribution&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;aws-1&#x2F;#compute-services&quot;&gt;Compute Services&lt;&#x2F;a&gt; - Where code runs&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;aws-1&#x2F;#storage&quot;&gt;Storage&lt;&#x2F;a&gt; - Where data lives&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;aws-1&#x2F;#observability&quot;&gt;Observability&lt;&#x2F;a&gt; - How to monitor&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aws-concepts-traditional-infrastructure&quot;&gt;AWS concepts → Traditional infrastructure&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;ve been managing Linux servers, you already know most of these concepts. AWS just wraps them in managed services with different names:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;AWS Service&#x2F;Concept&lt;&#x2F;th&gt;&lt;th&gt;Traditional Equivalent&lt;&#x2F;th&gt;&lt;th&gt;What&#x27;s Different?&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;EC2&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Physical server, VM (KVM&#x2F;VMware)&lt;&#x2F;td&gt;&lt;td&gt;Rent by the hour, no hardware to buy&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;VPC&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Network subnet, VLAN&lt;&#x2F;td&gt;&lt;td&gt;Software-defined, fully isolated per customer&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Security Groups&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;iptables&lt;&#x2F;code&gt; rules (instance-level)&lt;&#x2F;td&gt;&lt;td&gt;Stateful, attached to network interfaces&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Network ACLs&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;iptables&lt;&#x2F;code&gt; at router&#x2F;subnet level&lt;&#x2F;td&gt;&lt;td&gt;Stateless, numbered rules, processed in order&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;S3&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;File server (NFS, Samba), MinIO&lt;&#x2F;td&gt;&lt;td&gt;Object storage (not filesystem), infinite scale, HTTP API&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;EBS&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Hard drive, LVM volume&lt;&#x2F;td&gt;&lt;td&gt;Network-attached block storage, point-in-time snapshots&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;EFS&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;NFS share&lt;&#x2F;td&gt;&lt;td&gt;Managed NFS, auto-scaling, multi-AZ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;RDS&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;PostgreSQL server you installed&lt;&#x2F;td&gt;&lt;td&gt;AWS manages backups, patches, replication, HA&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Load Balancer (ALB&#x2F;NLB)&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Nginx, HAProxy, Apache &lt;code&gt;mod_proxy&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Fully managed, auto-scales, integrated health checks&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Auto Scaling&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Custom bash scripts watching &lt;code&gt;top&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Automatic instance scaling based on CloudWatch metrics&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;IAM&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&#x2F;etc&#x2F;passwd&lt;&#x2F;code&gt;, &lt;code&gt;sudo&lt;&#x2F;code&gt;, LDAP&#x2F;Active Directory&lt;&#x2F;td&gt;&lt;td&gt;Controls AWS API access, not just OS users&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;IAM Roles&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Service accounts, &lt;code&gt;systemd&lt;&#x2F;code&gt; user credentials&lt;&#x2F;td&gt;&lt;td&gt;Temporary credentials that auto-rotate&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CloudWatch Metrics&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Prometheus, Nagios, Zabbix, Grafana&lt;&#x2F;td&gt;&lt;td&gt;Pre-integrated with all AWS services&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CloudWatch Logs&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;syslog&lt;&#x2F;code&gt;, &lt;code&gt;journald&lt;&#x2F;code&gt;, ELK stack&lt;&#x2F;td&gt;&lt;td&gt;Centralized log aggregation, SQL-like queries&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CloudWatch Alarms&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Nagios alerts, &lt;code&gt;monit&lt;&#x2F;code&gt;, custom scripts&lt;&#x2F;td&gt;&lt;td&gt;Trigger actions (scaling, notifications, Lambda)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CloudTrail&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;auditd&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;var&#x2F;log&#x2F;audit&#x2F;audit.log&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Every AWS API call logged (who did what, when)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Lambda&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Cron jobs + shell scripts&lt;&#x2F;td&gt;&lt;td&gt;Event-driven functions, no server to manage&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Route 53&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;BIND, &lt;code&gt;dnsmasq&lt;&#x2F;code&gt;, PowerDNS&lt;&#x2F;td&gt;&lt;td&gt;Managed DNS with health checks and routing policies&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Regions&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Multiple data center locations&lt;&#x2F;td&gt;&lt;td&gt;Completely isolated, compliance&#x2F;data residency boundaries&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Availability Zones&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Separate racks&#x2F;power&#x2F;networking in same DC&lt;&#x2F;td&gt;&lt;td&gt;Physical separation within region, low-latency links&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;The trade-off&lt;&#x2F;strong&gt;: You give up control (can&#x27;t SSH into the Load Balancer) in exchange for less maintenance (AWS patches it for you). Whether that&#x27;s worth it depends on your team size, expertise, and what you&#x27;re trying to build. And if you understood everything inside the table above, you can stop here, I&#x27;m serious :\&lt;&#x2F;p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;want-to-know-more-okay&quot;&gt;Want to know more ? Okay&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;fundamentals&quot;&gt;Fundamentals&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;global-infrastructure&#x2F;latest&#x2F;regions&#x2F;aws-regions.html&quot;&gt;Regions&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; are geographically isolated clusters of data centers. Each region (e.g., &lt;code&gt;eu-west-3&lt;&#x2F;code&gt; for Paris, &lt;code&gt;us-east-1&lt;&#x2F;code&gt; for N. Virginia) operates independently. You choose a region based on:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Latency&lt;&#x2F;strong&gt; — closer to your users = faster response&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Compliance&lt;&#x2F;strong&gt; — data residency laws may require specific locations&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Service availability&lt;&#x2F;strong&gt; — not all services exist in all regions&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Pricing&lt;&#x2F;strong&gt; — costs vary by region&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;global-infrastructure&#x2F;latest&#x2F;regions&#x2F;aws-availability-zones.html&quot;&gt;Availability Zones (AZs)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; are physically separate data centers within a region, connected by low-latency links. Deploying across multiple Zones provides fault tolerance: if one data center fails, your application survives.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;organizations&#x2F;latest&#x2F;userguide&#x2F;orgs_introduction.html&quot;&gt;Organizations&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; is a service designed for central governance and management of multiple AWS accounts. They are useful for:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Isolating environments (dev&#x2F;staging&#x2F;prod)&lt;&#x2F;li&gt;
&lt;li&gt;Separating billing by department or project&lt;&#x2F;li&gt;
&lt;li&gt;Applying security policies across accounts&lt;&#x2F;li&gt;
&lt;li&gt;Consolidated billing with volume discounts&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;identity-and-access-management&quot;&gt;Identity and Access Management&lt;&#x2F;h3&gt;
&lt;p&gt;Before you start spinning up resources, you need to understand &lt;strong&gt;who can do what&lt;&#x2F;strong&gt; in your AWS account. This is where &lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;IAM&#x2F;latest&#x2F;UserGuide&#x2F;introduction.html&quot;&gt;IAM (Identity and Access Management)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; comes in.&lt;&#x2F;p&gt;
&lt;p&gt;IAM is AWS&#x27;s authentication and authorization service. It controls who can access your AWS resources and what actions they can perform. Get this wrong, and you&#x27;ll either lock yourself out or leave your infrastructure wide open to attackers.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Core IAM concepts:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Component&lt;&#x2F;th&gt;&lt;th&gt;Purpose&lt;&#x2F;th&gt;&lt;th&gt;When to Use&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;IAM&#x2F;latest&#x2F;UserGuide&#x2F;id_users.html&quot;&gt;Users&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Individual identities with permanent credentials&lt;&#x2F;td&gt;&lt;td&gt;Human access via Console&#x2F;CLI&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;IAM&#x2F;latest&#x2F;UserGuide&#x2F;id_groups.html&quot;&gt;Groups&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Collections of users with shared permissions&lt;&#x2F;td&gt;&lt;td&gt;Organizing users by function (developers, ops, analysts)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;IAM&#x2F;latest&#x2F;UserGuide&#x2F;id_roles.html&quot;&gt;Roles&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Temporary credentials that can be assumed&lt;&#x2F;td&gt;&lt;td&gt;Services, applications, cross-account access&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;IAM&#x2F;latest&#x2F;UserGuide&#x2F;access_policies.html&quot;&gt;Policies&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;JSON documents defining permissions&lt;&#x2F;td&gt;&lt;td&gt;Attach to users, groups, or roles&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;IAM&#x2F;latest&#x2F;UserGuide&#x2F;access_policies.html&quot;&gt;IAM Policies&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; are JSON documents that specify allowed or denied actions. Example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Version&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;2012-10-17&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Statement&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Effect&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Allow&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Action&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;s3:GetObject&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;s3:ListBucket&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Resource&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;arn:aws:s3:::my-research-data&#x2F;*&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  }]
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This policy allows reading objects from a specific S3 bucket, nothing more. That&#x27;s the &lt;strong&gt;principle of least privilege&lt;&#x2F;strong&gt;: grant only the minimum permissions needed to do the job.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why roles matter more than you think:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The biggest mistake beginners make is hardcoding AWS credentials in their applications. I should be honest with you here, yes I&#x27;ve done it when I was younger. But today, please, I&#x27;m telling you, don&#x27;t do this.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Example scenario&lt;&#x2F;strong&gt;: Your EC2 instance needs to read files from S3.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Wrong approach&lt;&#x2F;strong&gt;: Store AWS access keys in a config file on the instance.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Keys can be stolen if the instance is compromised&lt;&#x2F;li&gt;
&lt;li&gt;Keys don&#x27;t rotate automatically&lt;&#x2F;li&gt;
&lt;li&gt;Difficult to audit who used which credentials&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Right approach&lt;&#x2F;strong&gt;: Attach an IAM role with S3 read permissions to the EC2 instance.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;No credentials stored anywhere&lt;&#x2F;li&gt;
&lt;li&gt;Temporary credentials rotate automatically&lt;&#x2F;li&gt;
&lt;li&gt;CloudTrail logs show exactly which instance accessed which resources&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Root account protection:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;When you create an AWS account, you get a root user with unlimited access. This is dangerous. Best practices:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Enable MFA&lt;&#x2F;strong&gt; (Multi-Factor Authentication) on the root account&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Create IAM users&lt;&#x2F;strong&gt; for daily work, even for administrators&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Lock away root credentials&lt;&#x2F;strong&gt; - only use them for tasks that &lt;em&gt;require&lt;&#x2F;em&gt; root (billing, account closure)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;organizations&#x2F;latest&#x2F;userguide&#x2F;orgs_manage_policies_scps.html&quot;&gt;AWS Organizations and Service Control Policies (SCPs)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; add another layer: they set permission boundaries across multiple accounts. Even if an IAM policy allows an action, an SCP can block it at the organization level. Useful for enforcing compliance (e.g., &quot;no one can launch instances outside eu-west-3&quot;).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;In the biomedical research context:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You&#x27;d use IAM to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Give researchers read-only access to specific S3 buckets containing datasets&lt;&#x2F;li&gt;
&lt;li&gt;Allow the data engineering team to manage ETL pipelines (write access to certain resources)&lt;&#x2F;li&gt;
&lt;li&gt;Grant your analysis scripts (running on EC2&#x2F;Lambda) temporary credentials to access databases&lt;&#x2F;li&gt;
&lt;li&gt;Prevent anyone from accidentally exposing patient data by restricting public S3 bucket creation&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Security Groups (covered below) control &lt;em&gt;network&lt;&#x2F;em&gt; access. IAM controls &lt;em&gt;identity and authorization&lt;&#x2F;em&gt;. You need both.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;network&quot;&gt;Network&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;Maybe I did need this class after all. I&#x27;m having flashbacks... crimping tool... crossover cable... straight cable... cat5.... class C... IPV6... Layer 3... Layer 4....&lt;&#x2F;em&gt; Heeelp! \o&#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;vpc&#x2F;latest&#x2F;userguide&#x2F;what-is-amazon-vpc.html&quot;&gt;VPC (Virtual Private Cloud)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; is your isolated network within AWS. With a VPC you define:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;what-is&#x2F;cidr&#x2F;&quot;&gt;CIDR block&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: your IP range (e.g., &lt;code&gt;10.0.0.0&#x2F;16&lt;&#x2F;code&gt; gives you 65,536 IPs)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;vpc&#x2F;latest&#x2F;userguide&#x2F;configure-subnets.html&quot;&gt;Subnets&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: subdivisions of your VPC, placed in specific Zones
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Public subnets&lt;&#x2F;em&gt;: resources can have public IPs, direct internet access&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Private subnets&lt;&#x2F;em&gt;: no direct internet access, only internal communication&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Gateways:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;vpc&#x2F;latest&#x2F;userguide&#x2F;VPC_Internet_Gateway.html&quot;&gt;Internet Gateway (IGW)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: enables internet access for public subnets. Attach one to your VPC, add routes, done.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;vpc&#x2F;latest&#x2F;userguide&#x2F;vpc-nat-gateway.html&quot;&gt;NAT Gateway&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: lets private subnet resources reach the internet (for updates, API calls) without being directly reachable..&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Hybrid connectivity:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;vpn&#x2F;latest&#x2F;s2svpn&#x2F;VPC_VPN.html&quot;&gt;Site-to-Site VPN&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: encrypted tunnel between your on-premises network and AWS VPC. Quick to set up, uses public internet, variable latency.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;directconnect&#x2F;latest&#x2F;UserGuide&#x2F;Welcome.html&quot;&gt;AWS Direct Connect&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: dedicated physical connection to AWS. Consistent latency, higher bandwidth, but requires physical setup and contracts. Useful for heavy data transfer or strict latency requirements.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Network Security:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;AWS provides two complementary layers of network security: &lt;strong&gt;Security Groups&lt;&#x2F;strong&gt; and &lt;strong&gt;Network ACLs&lt;&#x2F;strong&gt;. Understanding when to use each is critical.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;vpc&#x2F;latest&#x2F;userguide&#x2F;vpc-security-groups.html&quot;&gt;Security Groups&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; are stateful firewalls attached to resources (EC2 instances, RDS databases, etc.). They act like bouncers at the door of individual servers. Define allowed inbound&#x2F;outbound traffic by port, protocol, and source. If you allow inbound traffic on port 80, the return traffic is automatically allowed—that&#x27;s what &quot;stateful&quot; means.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;vpc&#x2F;latest&#x2F;userguide&#x2F;vpc-network-acls.html&quot;&gt;Network ACLs (NACLs)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; are stateless firewalls at the subnet level. They filter traffic entering or leaving entire subnets. Rules are evaluated in numerical order (100, 200, 300...), and the first match wins. Unlike Security Groups, NACLs require explicit rules for both inbound and outbound traffic.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Security Groups vs. Network ACLs:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Feature&lt;&#x2F;th&gt;&lt;th&gt;Security Groups&lt;&#x2F;th&gt;&lt;th&gt;Network ACLs&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Scope&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Instance level (attached to ENI)&lt;&#x2F;td&gt;&lt;td&gt;Subnet level&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;State&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Stateful (return traffic auto-allowed)&lt;&#x2F;td&gt;&lt;td&gt;Stateless (must allow both directions)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Rules&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Only Allow rules&lt;&#x2F;td&gt;&lt;td&gt;Allow + Deny rules&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Evaluation&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;All rules evaluated&lt;&#x2F;td&gt;&lt;td&gt;Processed in order, first match wins&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Default behavior&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Deny all inbound, allow all outbound&lt;&#x2F;td&gt;&lt;td&gt;Allow everything&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Typical use&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Your primary security control&lt;&#x2F;td&gt;&lt;td&gt;Edge cases, compliance, IP blocking&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;When to use what:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Security Groups&lt;&#x2F;strong&gt; should be your default choice for 95% of scenarios:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Allow SSH (port 22) only from your office IP&lt;&#x2F;li&gt;
&lt;li&gt;Let web servers accept HTTP&#x2F;HTTPS from anywhere&lt;&#x2F;li&gt;
&lt;li&gt;Allow database connections only from application servers&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Network ACLs&lt;&#x2F;strong&gt; are for specific edge cases:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Block a known malicious IP range at the subnet boundary&lt;&#x2F;li&gt;
&lt;li&gt;Compliance requirements mandating subnet-level controls&lt;&#x2F;li&gt;
&lt;li&gt;Defense-in-depth: add a second layer of protection&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Example scenario - Blocking an attacking IP:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Your web servers (in a public subnet) are under attack from &lt;code&gt;203.0.113.0&#x2F;24&lt;&#x2F;code&gt;. Security Groups can only &lt;em&gt;allow&lt;&#x2F;em&gt; traffic, not deny it. Solution: add a NACL rule.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;NACL Inbound Rules (evaluated in order):
&lt;&#x2F;span&gt;&lt;span&gt;Rule 100: DENY   TCP   80   from 203.0.113.0&#x2F;24   (block attackers)
&lt;&#x2F;span&gt;&lt;span&gt;Rule 200: ALLOW  TCP   80   from 0.0.0.0&#x2F;0        (allow everyone else)
&lt;&#x2F;span&gt;&lt;span&gt;Rule *:   DENY   ALL   ALL  from 0.0.0.0&#x2F;0        (default deny)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Because NACLs are stateless, you also need outbound rules for responses:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;NACL Outbound Rules:
&lt;&#x2F;span&gt;&lt;span&gt;Rule 100: ALLOW  TCP  1024-65535  to 0.0.0.0&#x2F;0   (ephemeral ports)
&lt;&#x2F;span&gt;&lt;span&gt;Rule *:   DENY   ALL  ALL         to 0.0.0.0&#x2F;0    (default deny)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;1024-65535&lt;&#x2F;code&gt; range covers ephemeral ports used by client connections. Yes, this is annoying. This is why most people stick to Security Groups.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Pro tip:&lt;&#x2F;strong&gt; The default NACL in your VPC allows all traffic. Most AWS users never modify it. Only touch NACLs when you have &lt;em&gt;3&lt;&#x2F;em&gt; specific reasons.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;vpc&#x2F;latest&#x2F;userguide&#x2F;flow-logs.html&quot;&gt;Flow Logs&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Capture network traffic metadata (source&#x2F;destination IP, port, protocol, action) for debugging and audit. Essential for troubleshooting connectivity issues and security investigations. Send logs to CloudWatch or S3 for analysis.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;load-balancing&quot;&gt;Load Balancing&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;High Availability&lt;&#x2F;strong&gt; means your application stays up even when parts of the infrastructure fail. In AWS, this typically involves deploying across multiple Availability Zones and using load balancers to distribute traffic.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;elasticloadbalancing&#x2F;&quot;&gt;Elastic Load Balancing (ELB)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; automatically distributes incoming traffic across multiple targets. AWS offers several types:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Type&lt;&#x2F;th&gt;&lt;th&gt;Layer&lt;&#x2F;th&gt;&lt;th&gt;Best For&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;elasticloadbalancing&#x2F;latest&#x2F;application&#x2F;introduction.html&quot;&gt;Application Load Balancer (ALB)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Layer 7 (HTTP&#x2F;HTTPS)&lt;&#x2F;td&gt;&lt;td&gt;Web apps, microservices, content-based routing&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;elasticloadbalancing&#x2F;latest&#x2F;network&#x2F;introduction.html&quot;&gt;Network Load Balancer (NLB)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Layer 4 (TCP&#x2F;UDP)&lt;&#x2F;td&gt;&lt;td&gt;Ultra-low latency, millions of requests&#x2F;sec&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;elasticloadbalancing&#x2F;latest&#x2F;gateway&#x2F;introduction.html&quot;&gt;Gateway Load Balancer&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Layer 3&lt;&#x2F;td&gt;&lt;td&gt;Third-party virtual appliances (firewalls, IDS)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;autoscaling&#x2F;ec2&#x2F;userguide&#x2F;what-is-amazon-ec2-auto-scaling.html&quot;&gt;Auto Scaling&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; automatically adjusts the number of EC2 instances based on demand:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scheduled scaling&lt;&#x2F;strong&gt;: scale at predictable times (e.g., business hours)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Dynamic scaling&lt;&#x2F;strong&gt;: react to CloudWatch metrics (CPU, memory, custom metrics)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Predictive scaling&lt;&#x2F;strong&gt;: ML-based forecasting of future demand&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Multi-AZ resilience&lt;&#x2F;strong&gt;: Deploy instances across multiple AZs, place a load balancer in front, and Auto Scaling replaces failed instances automatically. This is the foundation of most production architectures on AWS.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;compute-services&quot;&gt;Compute Services&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Compute&lt;&#x2F;strong&gt; refers to the processing power needed to run applications. AWS offers several options depending on your level of control vs. convenience:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;ec2&#x2F;&quot;&gt;EC2 (Elastic Compute Cloud)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; — Virtual machines you fully control. Choose your OS, instance type (CPU&#x2F;RAM), and storage. Pricing models:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Model&lt;&#x2F;th&gt;&lt;th&gt;Description&lt;&#x2F;th&gt;&lt;th&gt;Savings&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;On-Demand&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Pay by the hour&#x2F;second, no commitment&lt;&#x2F;td&gt;&lt;td&gt;Baseline pricing&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Reserved&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;1 or 3-year commitment for steady workloads&lt;&#x2F;td&gt;&lt;td&gt;Up to 72% off&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Spot&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Bid on unused capacity, can be interrupted&lt;&#x2F;td&gt;&lt;td&gt;Up to 90% off&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Savings Plans&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Flexible commitment across instance families&lt;&#x2F;td&gt;&lt;td&gt;Up to 72% off&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;Container services&lt;&#x2F;strong&gt; — For containerized workloads:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;AmazonECS&#x2F;latest&#x2F;developerguide&#x2F;Welcome.html&quot;&gt;ECS (Elastic Container Service)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: AWS-native container orchestration. Simpler than Kubernetes, tightly integrated with AWS.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;eks&#x2F;latest&#x2F;userguide&#x2F;what-is-eks.html&quot;&gt;EKS (Elastic Kubernetes Service)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Managed Kubernetes. Use this if you need Kubernetes compatibility or already use K8s.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;fargate&#x2F;&quot;&gt;Fargate&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Serverless compute for containers. No EC2 instances to manage—just define CPU&#x2F;memory and run your containers.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;When to use what:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;EC2: Full control needed, legacy apps, specific OS requirements&lt;&#x2F;li&gt;
&lt;li&gt;ECS + Fargate: Simple containerized apps, AWS-native approach&lt;&#x2F;li&gt;
&lt;li&gt;EKS: Kubernetes expertise on the team, multi-cloud portability needed&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 400px&quot; src=&quot;&#x2F;images&#x2F;cloud-computing.jpg&quot; alt=&quot;Cloud computing&quot; title=&quot;Cloud computing&quot;&#x2F;&gt;
&lt;h3 id=&quot;storage&quot;&gt;Storage&lt;&#x2F;h3&gt;
&lt;p&gt;AWS offers different storage types for different use cases:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;s3&#x2F;&quot;&gt;Amazon S3&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; — Object storage for any type of data. Highly durable (11 nines), infinitely scalable. &lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;s3&#x2F;storage-classes&#x2F;&quot;&gt;Storage classes&lt;&#x2F;a&gt; optimize cost based on access patterns:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Class&lt;&#x2F;th&gt;&lt;th&gt;Access Pattern&lt;&#x2F;th&gt;&lt;th&gt;Retrieval&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;S3 Standard&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Frequent access&lt;&#x2F;td&gt;&lt;td&gt;Instant&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;S3 Intelligent-Tiering&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Unknown&#x2F;changing patterns&lt;&#x2F;td&gt;&lt;td&gt;Instant (auto-moves data)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;S3 Standard-IA&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Infrequent access&lt;&#x2F;td&gt;&lt;td&gt;Instant&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;s3&#x2F;storage-classes&#x2F;glacier&#x2F;&quot;&gt;S3 Glacier Instant&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Archive, rare access&lt;&#x2F;td&gt;&lt;td&gt;Milliseconds&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;S3 Glacier Flexible&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Archive&lt;&#x2F;td&gt;&lt;td&gt;Minutes to hours&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;S3 Glacier Deep Archive&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Long-term archive&lt;&#x2F;td&gt;&lt;td&gt;12-48 hours&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;Lifecycle policies&lt;&#x2F;strong&gt; automatically transition objects between classes or delete them after a period.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Block vs. File storage:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;ebs&#x2F;&quot;&gt;EBS (Elastic Block Store)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Block storage attached to a single EC2 instance. Think: hard drive for your VM. Great for databases.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;efs&#x2F;&quot;&gt;EFS (Elastic File System)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Shared file system mountable by multiple EC2 instances. Think: NFS. Great for shared application data.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Databases:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;AmazonRDS&#x2F;latest&#x2F;UserGuide&#x2F;Welcome.html&quot;&gt;Amazon RDS (Relational Database Service)&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; — Managed relational databases for PostgreSQL, &lt;em&gt;(and other database providers I won&#x27;t talk about because I am a free software advocate)&lt;&#x2F;em&gt;. AWS handles the operational heavy lifting: backups, patching, OS updates, and replication. You focus on schema design and queries.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;High Availability and scaling options:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Understanding the difference between &lt;strong&gt;Multi-AZ&lt;&#x2F;strong&gt; and &lt;strong&gt;Read Replicas&lt;&#x2F;strong&gt; is critical:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Feature&lt;&#x2F;th&gt;&lt;th&gt;Multi-AZ&lt;&#x2F;th&gt;&lt;th&gt;Read Replicas&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Purpose&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;High availability (failover)&lt;&#x2F;td&gt;&lt;td&gt;Read scaling, analytics&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Replication&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Synchronous (to standby in another AZ)&lt;&#x2F;td&gt;&lt;td&gt;Asynchronous (can lag slightly)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Failover&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Automatic (1-2 minutes)&lt;&#x2F;td&gt;&lt;td&gt;Manual promotion required&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Readable&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Standby is not accessible&lt;&#x2F;td&gt;&lt;td&gt;Yes, handle read traffic&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Use case&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Production databases requiring uptime&lt;&#x2F;td&gt;&lt;td&gt;Distribute read load, reporting queries&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Cost&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;~2x (paying for standby)&lt;&#x2F;td&gt;&lt;td&gt;Additional instance cost per replica&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;Multi-AZ deployment&lt;&#x2F;strong&gt;: Your primary database synchronously replicates to a standby instance in a different Availability Zone. If the primary fails (hardware issue, AZ outage), RDS automatically fails over to the standby. Your application reconnects to the same endpoint—no code changes needed. This is for &lt;strong&gt;disaster recovery&lt;&#x2F;strong&gt;, not performance.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Read Replicas&lt;&#x2F;strong&gt;: Create up to 15 read-only copies of your database. Use them to offload read traffic (analytics, reporting) from the primary. Replication is asynchronous, so there may be a slight lag (usually milliseconds to seconds). You can promote a replica to primary if needed, but it&#x27;s a manual operation.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;rds&#x2F;aurora&#x2F;&quot;&gt;Amazon Aurora&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; — AWS&#x27;s proprietary database engine, PostgreSQL compatible:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Performance&lt;&#x2F;strong&gt;: Up to 3x faster than PostgreSQL (according to AWS benchmarks)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Storage auto-scaling&lt;&#x2F;strong&gt;: Starts at 10GB, grows automatically up to 128TB in 10GB increments&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;High availability built-in&lt;&#x2F;strong&gt;: Data replicated 6 ways across 3 AZs automatically&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Read scaling&lt;&#x2F;strong&gt;: Up to 15 Aurora Replicas with sub-10ms replica lag&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Cost&lt;&#x2F;strong&gt;: More expensive than standard RDS, but better price-to-performance for demanding workloads&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.cloudzero.com&#x2F;blog&#x2F;aurora-vs-rds&#x2F;&quot;&gt;Aurora&lt;&#x2F;a&gt; is AWS&#x27;s recommended choice for new applications that need high performance and availability.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Backup Strategies:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;RDS provides two backup mechanisms:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;AmazonRDS&#x2F;latest&#x2F;UserGuide&#x2F;USER_WorkingWithAutomatedBackups.html&quot;&gt;Automated backups&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Enabled by default&lt;&#x2F;li&gt;
&lt;li&gt;Point-in-time recovery: restore your database to any second within the retention period (1-35 days)&lt;&#x2F;li&gt;
&lt;li&gt;Full daily backups + transaction logs&lt;&#x2F;li&gt;
&lt;li&gt;Deleted when you delete the RDS instance (unless you configure a final snapshot)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;AmazonRDS&#x2F;latest&#x2F;UserGuide&#x2F;USER_CreateSnapshot.html&quot;&gt;Manual snapshots&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;User-initiated, persist until you explicitly delete them&lt;&#x2F;li&gt;
&lt;li&gt;Useful before major changes (schema migrations, upgrades)&lt;&#x2F;li&gt;
&lt;li&gt;Can be copied across regions for disaster recovery&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;Pro tip&lt;&#x2F;strong&gt;: Before any risky operation (major version upgrade, schema change), create a manual snapshot. Automated backups might not cover you if the retention period expires.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;RDS vs. NoSQL:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Not all data fits the relational model. &lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;amazondynamodb&#x2F;latest&#x2F;developerguide&#x2F;Introduction.html&quot;&gt;Amazon DynamoDB&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; is AWS&#x27;s managed NoSQL database (key-value and document store):&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Feature&lt;&#x2F;th&gt;&lt;th&gt;RDS (SQL)&lt;&#x2F;th&gt;&lt;th&gt;DynamoDB (NoSQL)&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Data model&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Tables with fixed schema, relations&lt;&#x2F;td&gt;&lt;td&gt;Key-value &#x2F; JSON documents, flexible schema&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Queries&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Complex SQL (JOINs, aggregations)&lt;&#x2F;td&gt;&lt;td&gt;Simple key lookups, limited querying&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Scaling&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Vertical (bigger instance), Read Replicas&lt;&#x2F;td&gt;&lt;td&gt;Horizontal (automatic), virtually unlimited&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Transactions&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Full ACID support&lt;&#x2F;td&gt;&lt;td&gt;Limited transactions (single-item ACID, multi-item with conditions)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Best for&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Complex queries, reporting, traditional apps&lt;&#x2F;td&gt;&lt;td&gt;High-throughput simple queries, IoT, gaming, mobile backends&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Pricing&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;Pay for instance size (even if idle)&lt;&#x2F;td&gt;&lt;td&gt;Pay for storage + read&#x2F;write capacity used&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;When to use what:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RDS&lt;&#x2F;strong&gt;: You need SQL, complex queries, transactions, existing relational schema, or you&#x27;re migrating from on-premises MySQL&#x2F;PostgreSQL&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;DynamoDB&lt;&#x2F;strong&gt;: Key-value access patterns, need massive scale, unpredictable traffic spikes, single-digit millisecond latency requirements&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Most traditional applications (e-commerce, ERP, content management) use RDS. DynamoDB shines for high-scale, low-latency use cases where you don&#x27;t need complex querying.&lt;&#x2F;p&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 400px&quot; src=&quot;&#x2F;images&#x2F;cloud-storage.jpg&quot; alt=&quot;cloud storage&quot; title=&quot;cloud storage&quot;&#x2F;&gt;
&lt;h3 id=&quot;observability&quot;&gt;Observability&lt;&#x2F;h3&gt;
&lt;p&gt;Observability = understanding what&#x27;s happening inside your systems. AWS provides &lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;AmazonCloudWatch&#x2F;latest&#x2F;monitoring&#x2F;WhatIsCloudWatch.html&quot;&gt;Amazon CloudWatch&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; as the central service for this.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;AmazonCloudWatch&#x2F;latest&#x2F;monitoring&#x2F;working_with_metrics.html&quot;&gt;Metrics&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Numerical data points over time. AWS services automatically send metrics (CPU usage, network traffic, request counts). You can also publish custom metrics from your applications.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;AmazonCloudWatch&#x2F;latest&#x2F;logs&#x2F;WhatIsCloudWatchLogs.html&quot;&gt;Logs&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Centralized log storage and analysis. Stream logs from EC2, Lambda, containers, or any application. Use &lt;strong&gt;Log Insights&lt;&#x2F;strong&gt; to query across log groups with a SQL-like syntax.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;AmazonCloudWatch&#x2F;latest&#x2F;monitoring&#x2F;AlarmThatSendsEmail.html&quot;&gt;Alarms&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Watch metrics and trigger actions when thresholds are breached:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Send notifications via SNS (email, SMS, Slack)&lt;&#x2F;li&gt;
&lt;li&gt;Trigger Auto Scaling to add&#x2F;remove instances&lt;&#x2F;li&gt;
&lt;li&gt;Execute Lambda functions for custom remediation&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Example alarm&lt;&#x2F;strong&gt;: &quot;If average CPU &amp;gt; 80% for 5 minutes, add 2 instances and notify the ops team.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Beyond CloudWatch:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;xray&#x2F;&quot;&gt;AWS X-Ray&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Distributed tracing for microservices&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;cloudtrail&#x2F;&quot;&gt;CloudTrail&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Audit log of all API calls in your account&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 400px&quot; src=&quot;&#x2F;images&#x2F;cloud-observability.jpg&quot; alt=&quot;cloud observability&quot; title=&quot;cloud observability&quot;&#x2F;&gt;
&lt;br&gt;
&lt;h2 id=&quot;one-picture-is-worth-thousand-words&quot;&gt;One picture is worth thousand words&lt;&#x2F;h2&gt;


&lt;div class=&quot;aws-diagram-wrapper&quot;&gt;
    &lt;style&gt;
        .aws-diagram-wrapper {
            --aws-bg: #0d1117;
            --aws-bg-secondary: #161b22;
            --aws-bg-tertiary: #21262d;
            --aws-border: #30363d;
            --aws-text: #e6edf3;
            --aws-text-muted: #8b949e;
            --aws-orange: #ff9900;
            --aws-green: #238636;
            --aws-blue: #1f6feb;
            --aws-blue-light: #388bfd;
            --aws-purple: #a371f7;
            --aws-yellow: #f0883e;

            font-family: &#x27;IBM Plex Sans&#x27;, -apple-system, BlinkMacSystemFont, &#x27;Segoe UI&#x27;, sans-serif;
            background: var(--aws-bg);
            color: var(--aws-text);
            padding: 40px 20px;
            border-radius: 8px;
            margin: 30px 0;
        }

        .aws-diagram-wrapper * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        .aws-diagram-wrapper h1 {
            font-size: 1.6rem;
            font-weight: 600;
            margin-bottom: 8px;
            color: var(--aws-orange);
        }

        .aws-diagram-wrapper .subtitle {
            color: var(--aws-text-muted);
            font-size: 0.9rem;
            margin-bottom: 40px;
        }

        .aws-diagram-wrapper .diagram-container {
            position: relative;
            background: linear-gradient(180deg, var(--aws-bg-secondary) 0%, var(--aws-bg) 100%);
            border: 1px solid var(--aws-border);
            border-radius: 8px;
            padding: 30px;
            overflow-x: auto;
        }

        .aws-diagram-wrapper .diagram {
            display: flex;
            flex-direction: column;
            gap: 16px;
            min-width: 1100px;
        }

        .aws-diagram-wrapper .zone {
            border: 2px dashed var(--aws-border);
            border-radius: 8px;
            padding: 20px;
            position: relative;
        }

        .aws-diagram-wrapper .zone-label {
            position: absolute;
            top: -10px;
            left: 20px;
            background: var(--aws-bg);
            padding: 2px 12px;
            font-size: 0.7rem;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 1px;
            color: var(--aws-text-muted);
        }

        .aws-diagram-wrapper .zone.internet {
            border-color: var(--aws-green);
            background: rgba(35, 134, 54, 0.05);
        }

        .aws-diagram-wrapper .zone.vpc {
            border-color: var(--aws-blue);
            background: rgba(31, 111, 235, 0.03);
        }

        .aws-diagram-wrapper .zone.public-subnet {
            border-color: var(--aws-yellow);
            background: rgba(240, 136, 62, 0.05);
        }

        .aws-diagram-wrapper .zone.private-subnet {
            border-color: var(--aws-purple);
            background: rgba(163, 113, 247, 0.05);
        }

        .aws-diagram-wrapper .zone.az {
            border-color: var(--aws-blue-light);
            border-style: dotted;
            background: rgba(56, 139, 253, 0.03);
        }

        .aws-diagram-wrapper .row {
            display: flex;
            gap: 20px;
            align-items: flex-start;
        }

        .aws-diagram-wrapper .component {
            background: var(--aws-bg-tertiary);
            border: 1px solid var(--aws-border);
            border-radius: 6px;
            padding: 14px 18px;
            min-width: 130px;
            text-align: center;
            position: relative;
            transition: all 0.2s ease;
            cursor: pointer;
        }

        .aws-diagram-wrapper .component:hover {
            border-color: var(--aws-orange);
            transform: translateY(-2px);
            box-shadow: 0 4px 20px rgba(255, 153, 0, 0.15);
        }

        .aws-diagram-wrapper .component.active {
            border-color: var(--aws-orange);
            background: #2d333b;
        }

        .aws-diagram-wrapper .component-name {
            font-weight: 600;
            font-size: 0.85rem;
            margin-bottom: 6px;
            color: var(--aws-text);
        }

        .aws-diagram-wrapper .component-type {
            font-family: &#x27;JetBrains Mono&#x27;, &#x27;Fira Code&#x27;, monospace;
            font-size: 0.65rem;
            color: var(--aws-orange);
            background: rgba(255, 153, 0, 0.1);
            padding: 3px 8px;
            border-radius: 3px;
            display: inline-block;
        }

        .aws-diagram-wrapper .arrow-container {
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 8px 0;
        }

        .aws-diagram-wrapper .arrow {
            display: flex;
            align-items: center;
            gap: 8px;
            color: #6e7681;
            font-size: 0.7rem;
            font-family: &#x27;JetBrains Mono&#x27;, monospace;
        }

        .aws-diagram-wrapper .arrow-line {
            width: 50px;
            height: 2px;
            background: linear-gradient(90deg, var(--aws-border) 0%, var(--aws-orange) 50%, var(--aws-border) 100%);
            position: relative;
        }

        .aws-diagram-wrapper .arrow-line::after {
            content: &#x27;&gt;&#x27;;
            position: absolute;
            right: -6px;
            top: -7px;
            color: var(--aws-orange);
            font-size: 0.7rem;
            font-weight: bold;
        }

        .aws-diagram-wrapper .arrow-down {
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .aws-diagram-wrapper .arrow-down .arrow-line {
            width: 2px;
            height: 30px;
            background: linear-gradient(180deg, var(--aws-border) 0%, var(--aws-orange) 50%, var(--aws-border) 100%);
        }

        .aws-diagram-wrapper .arrow-down .arrow-line::after {
            content: &#x27;v&#x27;;
            right: -5px;
            top: auto;
            bottom: -10px;
            font-size: 0.6rem;
        }

        .aws-diagram-wrapper .flex-center {
            display: flex;
            justify-content: center;
            align-items: center;
        }

        .aws-diagram-wrapper .flex-between {
            display: flex;
            justify-content: space-between;
            align-items: flex-start;
        }

        .aws-diagram-wrapper .flex-col {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 8px;
        }

        .aws-diagram-wrapper .info-panel {
            margin-top: 30px;
            background: var(--aws-bg-secondary);
            border: 1px solid var(--aws-border);
            border-radius: 8px;
            padding: 24px;
            min-height: 180px;
        }

        .aws-diagram-wrapper .info-panel h3 {
            font-size: 1rem;
            color: var(--aws-orange);
            margin-bottom: 12px;
        }

        .aws-diagram-wrapper .info-panel .description {
            color: var(--aws-text-muted);
            line-height: 1.7;
            margin-bottom: 16px;
            font-size: 0.9rem;
        }

        .aws-diagram-wrapper .info-panel .analogy {
            background: var(--aws-bg-tertiary);
            border-left: 3px solid var(--aws-green);
            padding: 12px 16px;
            border-radius: 0 6px 6px 0;
            margin-bottom: 16px;
        }

        .aws-diagram-wrapper .info-panel .analogy-label {
            font-size: 0.65rem;
            text-transform: uppercase;
            letter-spacing: 1px;
            color: var(--aws-green);
            margin-bottom: 6px;
        }

        .aws-diagram-wrapper .info-panel .analogy p {
            font-size: 0.85rem;
            color: var(--aws-text-muted);
        }

        .aws-diagram-wrapper .info-panel .code {
            font-family: &#x27;JetBrains Mono&#x27;, &#x27;Fira Code&#x27;, monospace;
            font-size: 0.75rem;
            background: var(--aws-bg);
            padding: 12px 16px;
            border-radius: 6px;
            color: #79c0ff;
            overflow-x: auto;
            line-height: 1.5;
        }

        .aws-diagram-wrapper .storage-section {
            display: flex;
            gap: 20px;
            margin-top: 16px;
        }

        .aws-diagram-wrapper .storage-group {
            flex: 1;
            background: var(--aws-bg-secondary);
            border: 1px solid var(--aws-border);
            border-radius: 6px;
            padding: 16px;
        }

        .aws-diagram-wrapper .storage-group h4 {
            font-size: 0.75rem;
            color: var(--aws-text-muted);
            margin-bottom: 12px;
            text-transform: uppercase;
            letter-spacing: 1px;
        }

        .aws-diagram-wrapper .storage-items {
            display: flex;
            gap: 12px;
            flex-wrap: wrap;
        }

        .aws-diagram-wrapper .legend {
            display: flex;
            gap: 24px;
            flex-wrap: wrap;
            margin-top: 20px;
            padding: 14px;
            background: var(--aws-bg-secondary);
            border-radius: 6px;
        }

        .aws-diagram-wrapper .legend-item {
            display: flex;
            align-items: center;
            gap: 8px;
            font-size: 0.75rem;
            color: var(--aws-text-muted);
        }

        .aws-diagram-wrapper .legend-color {
            width: 14px;
            height: 14px;
            border-radius: 3px;
            border: 2px dashed;
        }

        .aws-diagram-wrapper .legend-color.internet { border-color: var(--aws-green); background: rgba(35, 134, 54, 0.2); }
        .aws-diagram-wrapper .legend-color.vpc { border-color: var(--aws-blue); background: rgba(31, 111, 235, 0.2); }
        .aws-diagram-wrapper .legend-color.public { border-color: var(--aws-yellow); background: rgba(240, 136, 62, 0.2); }
        .aws-diagram-wrapper .legend-color.private { border-color: var(--aws-purple); background: rgba(163, 113, 247, 0.2); }

        .aws-diagram-wrapper .click-hint {
            text-align: center;
            color: #6e7681;
            font-size: 0.75rem;
            margin-top: 14px;
        }

        .aws-diagram-wrapper .or-divider {
            font-size: 0.65rem;
            color: #6e7681;
            font-style: italic;
        }
    &lt;&#x2F;style&gt;

    &lt;h1&gt;AWS Architecture - Overview&lt;&#x2F;h1&gt;
    &lt;p class=&quot;subtitle&quot;&gt;Click on a component to see details and analogy with your current stack&lt;&#x2F;p&gt;

    &lt;div class=&quot;diagram-container&quot;&gt;
        &lt;div class=&quot;diagram&quot;&gt;

            &lt;!-- Internet Zone --&gt;
            &lt;div class=&quot;zone internet&quot;&gt;
                &lt;span class=&quot;zone-label&quot;&gt;Internet&lt;&#x2F;span&gt;
                &lt;div class=&quot;flex-center&quot;&gt;
                    &lt;div class=&quot;component&quot; data-component=&quot;users&quot;&gt;
                        &lt;div class=&quot;component-name&quot;&gt;Users&lt;&#x2F;div&gt;
                        &lt;div class=&quot;component-type&quot;&gt;Front &amp; mobile Apps&lt;&#x2F;div&gt;
                    &lt;&#x2F;div&gt;
                    &lt;div class=&quot;arrow&quot;&gt;
                        &lt;div class=&quot;arrow-line&quot;&gt;&lt;&#x2F;div&gt;
                        &lt;span&gt;HTTPS&lt;&#x2F;span&gt;
                        &lt;div class=&quot;arrow-line&quot;&gt;&lt;&#x2F;div&gt;
                    &lt;&#x2F;div&gt;
                    &lt;div class=&quot;component&quot; data-component=&quot;route53&quot;&gt;
                        &lt;div class=&quot;component-name&quot;&gt;Route 53&lt;&#x2F;div&gt;
                        &lt;div class=&quot;component-type&quot;&gt;DNS&lt;&#x2F;div&gt;
                    &lt;&#x2F;div&gt;
                &lt;&#x2F;div&gt;
            &lt;&#x2F;div&gt;

            &lt;!-- VPC --&gt;
            &lt;div class=&quot;zone vpc&quot;&gt;
                &lt;span class=&quot;zone-label&quot;&gt;VPC (10.0.0.0&#x2F;16)&lt;&#x2F;span&gt;

                &lt;div class=&quot;flex-between&quot; style=&quot;gap: 20px;&quot;&gt;

                    &lt;!-- AZ 1 --&gt;
                    &lt;div class=&quot;zone az&quot; style=&quot;flex: 1;&quot;&gt;
                        &lt;span class=&quot;zone-label&quot;&gt;AZ-1 (eu-west-3a)&lt;&#x2F;span&gt;

                        &lt;!-- Public Subnet AZ1 --&gt;
                        &lt;div class=&quot;zone public-subnet&quot; style=&quot;margin-bottom: 15px;&quot;&gt;
                            &lt;span class=&quot;zone-label&quot;&gt;Public Subnet (10.0.1.0&#x2F;24)&lt;&#x2F;span&gt;
                            &lt;div class=&quot;flex-col&quot;&gt;
                                &lt;div class=&quot;component&quot; data-component=&quot;igw&quot;&gt;
                                    &lt;div class=&quot;component-name&quot;&gt;Internet Gateway&lt;&#x2F;div&gt;
                                    &lt;div class=&quot;component-type&quot;&gt;IGW&lt;&#x2F;div&gt;
                                &lt;&#x2F;div&gt;
                                &lt;div class=&quot;arrow-down&quot;&gt;&lt;div class=&quot;arrow-line&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
                                &lt;div class=&quot;component&quot; data-component=&quot;alb&quot;&gt;
                                    &lt;div class=&quot;component-name&quot;&gt;Load Balancer&lt;&#x2F;div&gt;
                                    &lt;div class=&quot;component-type&quot;&gt;ALB &#x2F; NLB&lt;&#x2F;div&gt;
                                &lt;&#x2F;div&gt;
                                &lt;div class=&quot;component&quot; data-component=&quot;nat&quot;&gt;
                                    &lt;div class=&quot;component-name&quot;&gt;NAT Gateway&lt;&#x2F;div&gt;
                                    &lt;div class=&quot;component-type&quot;&gt;NAT&lt;&#x2F;div&gt;
                                &lt;&#x2F;div&gt;
                            &lt;&#x2F;div&gt;
                        &lt;&#x2F;div&gt;

                        &lt;!-- Private Subnet AZ1 --&gt;
                        &lt;div class=&quot;zone private-subnet&quot;&gt;
                            &lt;span class=&quot;zone-label&quot;&gt;Private Subnet (10.0.10.0&#x2F;24)&lt;&#x2F;span&gt;
                            &lt;div class=&quot;flex-col&quot;&gt;
                                &lt;div class=&quot;component&quot; data-component=&quot;ec2&quot;&gt;
                                    &lt;div class=&quot;component-name&quot;&gt;EC2 Instance&lt;&#x2F;div&gt;
                                    &lt;div class=&quot;component-type&quot;&gt;t3.medium&lt;&#x2F;div&gt;
                                &lt;&#x2F;div&gt;
                                &lt;div class=&quot;or-divider&quot;&gt;or&lt;&#x2F;div&gt;
                                &lt;div class=&quot;component&quot; data-component=&quot;ecs&quot;&gt;
                                    &lt;div class=&quot;component-name&quot;&gt;ECS &#x2F; Fargate&lt;&#x2F;div&gt;
                                    &lt;div class=&quot;component-type&quot;&gt;Container&lt;&#x2F;div&gt;
                                &lt;&#x2F;div&gt;
                            &lt;&#x2F;div&gt;
                        &lt;&#x2F;div&gt;
                    &lt;&#x2F;div&gt;

                    &lt;!-- AZ 2 --&gt;
                    &lt;div class=&quot;zone az&quot; style=&quot;flex: 1;&quot;&gt;
                        &lt;span class=&quot;zone-label&quot;&gt;AZ-2 (eu-west-3b)&lt;&#x2F;span&gt;

                        &lt;!-- Public Subnet AZ2 --&gt;
                        &lt;div class=&quot;zone public-subnet&quot; style=&quot;margin-bottom: 15px;&quot;&gt;
                            &lt;span class=&quot;zone-label&quot;&gt;Public Subnet (10.0.2.0&#x2F;24)&lt;&#x2F;span&gt;
                            &lt;div class=&quot;flex-col&quot;&gt;
                                &lt;div class=&quot;component&quot; data-component=&quot;alb&quot;&gt;
                                    &lt;div class=&quot;component-name&quot;&gt;Load Balancer&lt;&#x2F;div&gt;
                                    &lt;div class=&quot;component-type&quot;&gt;ALB (replica)&lt;&#x2F;div&gt;
                                &lt;&#x2F;div&gt;
                            &lt;&#x2F;div&gt;
                        &lt;&#x2F;div&gt;

                        &lt;!-- Private Subnet AZ2 --&gt;
                        &lt;div class=&quot;zone private-subnet&quot;&gt;
                            &lt;span class=&quot;zone-label&quot;&gt;Private Subnet (10.0.20.0&#x2F;24)&lt;&#x2F;span&gt;
                            &lt;div class=&quot;flex-col&quot;&gt;
                                &lt;div class=&quot;component&quot; data-component=&quot;ec2&quot;&gt;
                                    &lt;div class=&quot;component-name&quot;&gt;EC2 Instance&lt;&#x2F;div&gt;
                                    &lt;div class=&quot;component-type&quot;&gt;t3.medium&lt;&#x2F;div&gt;
                                &lt;&#x2F;div&gt;
                                &lt;div class=&quot;arrow-down&quot;&gt;&lt;div class=&quot;arrow-line&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
                                &lt;div class=&quot;component&quot; data-component=&quot;rds&quot;&gt;
                                    &lt;div class=&quot;component-name&quot;&gt;RDS PostgreSQL&lt;&#x2F;div&gt;
                                    &lt;div class=&quot;component-type&quot;&gt;Multi-AZ&lt;&#x2F;div&gt;
                                &lt;&#x2F;div&gt;
                            &lt;&#x2F;div&gt;
                        &lt;&#x2F;div&gt;
                    &lt;&#x2F;div&gt;
                &lt;&#x2F;div&gt;
            &lt;&#x2F;div&gt;

            &lt;!-- Storage &amp; Monitoring --&gt;
            &lt;div class=&quot;storage-section&quot;&gt;
                &lt;div class=&quot;storage-group&quot;&gt;
                    &lt;h4&gt;Storage&lt;&#x2F;h4&gt;
                    &lt;div class=&quot;storage-items&quot;&gt;
                        &lt;div class=&quot;component&quot; data-component=&quot;s3&quot;&gt;
                            &lt;div class=&quot;component-name&quot;&gt;S3 Bucket&lt;&#x2F;div&gt;
                            &lt;div class=&quot;component-type&quot;&gt;Object Storage&lt;&#x2F;div&gt;
                        &lt;&#x2F;div&gt;
                        &lt;div class=&quot;component&quot; data-component=&quot;ebs&quot;&gt;
                            &lt;div class=&quot;component-name&quot;&gt;EBS Volume&lt;&#x2F;div&gt;
                            &lt;div class=&quot;component-type&quot;&gt;Block Storage&lt;&#x2F;div&gt;
                        &lt;&#x2F;div&gt;
                        &lt;div class=&quot;component&quot; data-component=&quot;efs&quot;&gt;
                            &lt;div class=&quot;component-name&quot;&gt;EFS&lt;&#x2F;div&gt;
                            &lt;div class=&quot;component-type&quot;&gt;File System&lt;&#x2F;div&gt;
                        &lt;&#x2F;div&gt;
                    &lt;&#x2F;div&gt;
                &lt;&#x2F;div&gt;
                &lt;div class=&quot;storage-group&quot;&gt;
                    &lt;h4&gt;Monitoring and Streaming&lt;&#x2F;h4&gt;
                    &lt;div class=&quot;storage-items&quot;&gt;
                        &lt;div class=&quot;component&quot; data-component=&quot;cloudwatch&quot;&gt;
                            &lt;div class=&quot;component-name&quot;&gt;CloudWatch&lt;&#x2F;div&gt;
                            &lt;div class=&quot;component-type&quot;&gt;Monitoring&lt;&#x2F;div&gt;
                        &lt;&#x2F;div&gt;
                        &lt;div class=&quot;component&quot; data-component=&quot;msk&quot;&gt;
                            &lt;div class=&quot;component-name&quot;&gt;MSK (Kafka)&lt;&#x2F;div&gt;
                            &lt;div class=&quot;component-type&quot;&gt;Streaming&lt;&#x2F;div&gt;
                        &lt;&#x2F;div&gt;
                    &lt;&#x2F;div&gt;
                &lt;&#x2F;div&gt;
            &lt;&#x2F;div&gt;
        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    &lt;!-- Legend --&gt;
    &lt;div class=&quot;legend&quot;&gt;
        &lt;div class=&quot;legend-item&quot;&gt;
            &lt;div class=&quot;legend-color internet&quot;&gt;&lt;&#x2F;div&gt;
            &lt;span&gt;Internet (public access)&lt;&#x2F;span&gt;
        &lt;&#x2F;div&gt;
        &lt;div class=&quot;legend-item&quot;&gt;
            &lt;div class=&quot;legend-color vpc&quot;&gt;&lt;&#x2F;div&gt;
            &lt;span&gt;VPC (your private network)&lt;&#x2F;span&gt;
        &lt;&#x2F;div&gt;
        &lt;div class=&quot;legend-item&quot;&gt;
            &lt;div class=&quot;legend-color public&quot;&gt;&lt;&#x2F;div&gt;
            &lt;span&gt;Public Subnet (exposed)&lt;&#x2F;span&gt;
        &lt;&#x2F;div&gt;
        &lt;div class=&quot;legend-item&quot;&gt;
            &lt;div class=&quot;legend-color private&quot;&gt;&lt;&#x2F;div&gt;
            &lt;span&gt;Private Subnet (protected)&lt;&#x2F;span&gt;
        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    &lt;p class=&quot;click-hint&quot;&gt;Click on a component to see details&lt;&#x2F;p&gt;

    &lt;!-- Info Panel --&gt;
    &lt;div class=&quot;info-panel&quot; id=&quot;aws-info-panel&quot;&gt;
        &lt;h3&gt;Select a component&lt;&#x2F;h3&gt;
        &lt;p class=&quot;description&quot;&gt;
            Click on any element of the diagram to see a detailed explanation
            and the equivalent in your current environment (Nginx, Django, PostgreSQL...).
        &lt;&#x2F;p&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;

&lt;script&gt;
(function() {
    const componentInfo = {
        users: {
            title: &quot;Users &#x2F; Clients&quot;,
            description: &quot;The users who access your applications from the Internet. This could be health workers using our &lt;a href=&#x27;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;&#x27;&gt;syndromic surveillance system&lt;&#x2F;a&gt;.&quot;,
            analogy: &quot;It&#x27;s the same as now - your users typing the URL in their browser or systems calling your REST API.&quot;,
            code: &quot;curl https:&#x2F;&#x2F;surveillance.pasteur.sn&#x2F;api&#x2F;v1&#x2F;cases&#x2F;&quot;
        },
        route53: {
            title: &quot;Route 53 - DNS Service&quot;,
            description: &quot;AWS&#x27;s managed DNS service. It translates domain names (surveillance.pasteur.sn) into IP addresses. Can perform health checking and intelligent routing (geolocation, failover).&quot;,
            analogy: &quot;Equivalent to your current DNS (maybe managed by your registrar or Cloudflare). The difference: Route 53 integrates natively with other AWS services.&quot;,
            code: &quot;# Example record&lt;br&gt;surveillance.pasteur.sn  A  -&gt; ALB (alias)&quot;
        },
        igw: {
            title: &quot;Internet Gateway (IGW)&quot;,
            description: &quot;The gateway in and out of your VPC to the Internet. Without IGW, nothing in your VPC can communicate with the outside world. There is ONE per VPC.&quot;,
            analogy: &quot;It&#x27;s like the router&#x2F;firewall of your datacenter that connects your internal network to the Internet. Like your platform&#x27;s main gateway.&quot;,
            code: &quot;# One VPC = One IGW&lt;br&gt;aws ec2 create-internet-gateway&quot;
        },
        alb: {
            title: &quot;Application Load Balancer (ALB &#x2F; NLB)&quot;,
            description: &quot;Distributes traffic between multiple instances. ALB = Layer 7 (HTTP), understands URLs and can route &#x2F;api to one group, &#x2F;admin to another. NLB = Layer 4 (TCP), faster but less intelligent.&quot;,
            analogy: &quot;It&#x27;s your Nginx in reverse proxy mode, but managed and automatically scalable. No need to manage the nginx.conf file anymore!&quot;,
            code: &quot;# Nginx equivalent&lt;br&gt;upstream django {&lt;br&gt;    server 10.0.10.5:8000;&lt;br&gt;    server 10.0.20.5:8000;&lt;br&gt;}&lt;br&gt;location &#x2F; {&lt;br&gt;    proxy_pass http:&#x2F;&#x2F;django;&lt;br&gt;}&quot;
        },
        nat: {
            title: &quot;NAT Gateway&quot;,
            description: &quot;Allows resources in a PRIVATE subnet to access the Internet (for updates, external APIs) WITHOUT being accessible from the Internet. Outgoing traffic goes through NAT, but no incoming traffic is possible.&quot;,
            analogy: &quot;Like when your Django server (behind a firewall) can do &#x27;pip install&#x27; or call the Africa&#x27;s Talking API, but no one can access that server directly from the Internet.&quot;,
            code: &quot;# From your private EC2, this works:&lt;br&gt;curl https:&#x2F;&#x2F;api.africastalking.com&#x2F;send&lt;br&gt;&lt;br&gt;# But from the Internet, impossible to reach the EC2&quot;
        },
        ec2: {
            title: &quot;EC2 - Elastic Compute Cloud&quot;,
            description: &quot;Virtual machines. You choose the type (t3.medium = 2 vCPU, 4 GB RAM), the OS (Ubuntu, Amazon Linux), and you pay per hour. On Demand = flexible, Reserved = -60%, Spot = -90% but interruptible.&quot;,
            analogy: &quot;It&#x27;s exactly like your current VPS or physical servers, but elastic. You can create 10 in 2 minutes, and delete them afterwards.&quot;,
            code: &quot;# Equivalent to your current server&lt;br&gt;Ubuntu 22.04&lt;br&gt;2 vCPU, 4 GB RAM&lt;br&gt;Django + Gunicorn + your code&quot;
        },
        ecs: {
            title: &quot;ECS &#x2F; EKS &#x2F; Fargate - Containers&quot;,
            description: &quot;ECS = AWS container orchestrator. EKS = Managed Kubernetes. Fargate = serverless (no servers to manage). You package your Django in a Docker image, and AWS handles the rest.&quot;,
            analogy: &quot;If you&#x27;re using Docker now with docker-compose, ECS is the same but in production and scalable. No need to SSH into the server to do &#x27;docker pull&#x27;.&quot;,
            code: &quot;# Dockerfile&lt;br&gt;FROM python:3.11&lt;br&gt;COPY . &#x2F;app&lt;br&gt;RUN pip install -r requirements.txt&lt;br&gt;CMD [\&quot;gunicorn\&quot;, \&quot;config.wsgi:application\&quot;]&quot;
        },
        rds: {
            title: &quot;RDS - Relational Database Service&quot;,
            description: &quot;Managed databases (PostgreSQL, MySQL, etc.). AWS handles automatic backups, security patches, Multi-AZ replication. You focus on your queries, not maintenance.&quot;,
            analogy: &quot;It&#x27;s your current PostgreSQL, but you no longer have to worry about pg_dump, version upgrades, or replication. AWS does everything.&quot;,
            code: &quot;# Django settings.py&lt;br&gt;DATABASES = {&lt;br&gt;    &#x27;default&#x27;: {&lt;br&gt;        &#x27;ENGINE&#x27;: &#x27;django.db.backends.postgresql&#x27;,&lt;br&gt;        &#x27;HOST&#x27;: &#x27;mydb.xxxxx.eu-west-3.rds.amazonaws.com&#x27;,&lt;br&gt;        &#x27;NAME&#x27;: &#x27;surveillance_db&#x27;,&lt;br&gt;    }&lt;br&gt;}&quot;
        },
        s3: {
            title: &quot;S3 - Simple Storage Service&quot;,
            description: &quot;Unlimited object storage. Perfect for static files, backups, media uploads. Not a classic file system (no mkdir), but &#x27;buckets&#x27; and &#x27;objects&#x27; with URLs.&quot;,
            analogy: &quot;Replaces your &#x2F;var&#x2F;www&#x2F;media&#x2F; folder for Django uploads. No more disk space issues, and your files are accessible via URL directly.&quot;,
            code: &quot;# Django settings with django-storages&lt;br&gt;DEFAULT_FILE_STORAGE = &#x27;storages.backends.s3boto3.S3Boto3Storage&#x27;&lt;br&gt;AWS_STORAGE_BUCKET_NAME = &#x27;ipd-surveillance-media&#x27;&quot;
        },
        ebs: {
            title: &quot;EBS - Elastic Block Store&quot;,
            description: &quot;Virtual hard drives attached to an EC2 instance. Like your server&#x27;s SSD. Persistent (data remains even if EC2 is stopped). Different types: gp3 (general), io2 (high perf), st1 (cheap HDD).&quot;,
            analogy: &quot;It&#x27;s exactly your current server&#x27;s hard drive. &#x2F;dev&#x2F;sda1 but in the cloud. If your EC2 dies, you can attach the EBS to a new instance.&quot;,
            code: &quot;# On your EC2&lt;br&gt;df -h&lt;br&gt;&#x2F;dev&#x2F;nvme0n1p1  100G   45G   55G  45% &#x2F;&quot;
        },
        efs: {
            title: &quot;EFS - Elastic File System&quot;,
            description: &quot;File system shared between MULTIPLE EC2 instances. Like a NAS. Useful when multiple servers need to access the same files (ex: shared uploads, common source code).&quot;,
            analogy: &quot;Like an NFS share between your servers. If you have 3 Django instances that all need to see the same uploaded files, EFS solves this problem.&quot;,
            code: &quot;# Mounted on multiple EC2&lt;br&gt;mount -t nfs4 fs-xxxxx.efs.eu-west-3.amazonaws.com:&#x2F; &#x2F;mnt&#x2F;shared&quot;
        },
        cloudwatch: {
            title: &quot;CloudWatch - Monitoring&quot;,
            description: &quot;Collects metrics (CPU, RAM, requests), centralizes logs, and triggers alerts. Built-in dashboard. Can trigger automatic actions (ex: scale up if CPU &gt; 80%).&quot;,
            analogy: &quot;Combines htop + tail -f &#x2F;var&#x2F;log + your alert system. But everything is centralized and you can create visual dashboards.&quot;,
            code: &quot;# Alert example&lt;br&gt;If CPUUtilization &gt; 80% for 5 min&lt;br&gt;-&gt; Send email to ops@pasteur.sn&lt;br&gt;-&gt; Add 2 instances to Auto Scaling Group&quot;
        },
        msk: {
            title: &quot;MSK - Managed Streaming for Kafka&quot;,
            description: &quot;Apache Kafka managed by AWS. For real-time data streaming, data pipelines, or event-driven architecture. Useful for processing millions of events per second.&quot;,
            analogy: &quot;Imagine each suspected case report generates an &#x27;event&#x27; that must be processed in real-time to trigger epidemiological alerts. Kafka enables this continuous flow of data.&quot;,
            code: &quot;# Producer (notification system)&lt;br&gt;producer.send(&#x27;alerts-topic&#x27;, {&lt;br&gt;    &#x27;type&#x27;: &#x27;suspected_case&#x27;,&lt;br&gt;    &#x27;disease&#x27;: &#x27;cholera&#x27;,&lt;br&gt;    &#x27;location&#x27;: &#x27;dakar&#x27;,&lt;br&gt;    &#x27;timestamp&#x27;: &#x27;2025-01-31T10:30:00Z&#x27;&lt;br&gt;})&quot;
        }
    };

    const wrapper = document.querySelector(&#x27;.aws-diagram-wrapper&#x27;);
    const panel = wrapper.querySelector(&#x27;#aws-info-panel&#x27;);

    wrapper.querySelectorAll(&#x27;.component&#x27;).forEach(comp =&gt; {
        comp.addEventListener(&#x27;click&#x27;, function() {
            const componentId = this.dataset.component;
            const info = componentInfo[componentId];

            if (info) {
                wrapper.querySelectorAll(&#x27;.component&#x27;).forEach(c =&gt; c.classList.remove(&#x27;active&#x27;));
                wrapper.querySelectorAll(`[data-component=&quot;${componentId}&quot;]`).forEach(c =&gt; c.classList.add(&#x27;active&#x27;));

                panel.innerHTML = `
                    &lt;h3&gt;${info.title}&lt;&#x2F;h3&gt;
                    &lt;p class=&quot;description&quot;&gt;${info.description}&lt;&#x2F;p&gt;
                    &lt;div class=&quot;analogy&quot;&gt;
                        &lt;div class=&quot;analogy-label&quot;&gt;Equivalent dans ton stack actuel&lt;&#x2F;div&gt;
                        &lt;p&gt;${info.analogy}&lt;&#x2F;p&gt;
                    &lt;&#x2F;div&gt;
                    &lt;div class=&quot;code&quot;&gt;${info.code.replace(&#x2F;\n&#x2F;g, &#x27;&lt;br&gt;&#x27;)}&lt;&#x2F;div&gt;
                `;
            }
        });
    });
})();
&lt;&#x2F;script&gt;
&lt;h2 id=&quot;how-to-practice&quot;&gt;How to practice&lt;&#x2F;h2&gt;
&lt;p&gt;You don&#x27;t need a corporate account to learn AWS:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;free&#x2F;&quot;&gt;AWS Free Tier&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: The real AWS, free for 12 months (with limits). Great for hands-on experience with actual services.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;localstack.cloud&#x2F;&quot;&gt;LocalStack&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: AWS emulator running on your laptop. Spin up S3, Lambda, DynamoDB locally. No cloud costs.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;minikube.sigs.k8s.io&#x2F;&quot;&gt;Minikube&lt;&#x2F;a&gt; &#x2F; &lt;a href=&quot;https:&#x2F;&#x2F;kind.sigs.k8s.io&#x2F;&quot;&gt;Kind&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Local Kubernetes clusters for learning EKS concepts.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;k3s.io&#x2F;&quot;&gt;K3s&lt;&#x2F;a&gt; &#x2F; &lt;a href=&quot;https:&#x2F;&#x2F;k3d.io&#x2F;&quot;&gt;K3d&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Lightweight Kubernetes distributions, perfect for development and edge deployments.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.podman.io&#x2F;en&#x2F;latest&#x2F;markdown&#x2F;podman-compose.1.html&quot;&gt;Podman Compose&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: Simulate architectures with containers (PostgreSQL, Redis, Nginx). Understand the concepts before going managed.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;The key insight is this: everything you&#x27;ve been doing manually for years, fingers in the nose, eyes closed (configuring Nginx, Gunicorn, PostgreSQL, managing users, monitoring logs), AWS offers it as managed services. You&#x27;re trading full control for less maintenance.&lt;&#x2F;p&gt;
&lt;p&gt;Is that trade-off worth it? It depends. For a small team that needs to move fast and can&#x27;t afford dedicated ops, managed services make sense. For organizations with specific compliance needs or those who want to avoid vendor lock-in, the calculus changes.&lt;&#x2F;p&gt;
&lt;p&gt;Either way, understanding these concepts matters, whether you end up using AWS, another cloud, or staying on-premises.&lt;&#x2F;p&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 400px&quot; src=&quot;&#x2F;images&#x2F;there_is_no_cloud.png&quot; alt=&quot;There is no cloud&quot; title=&quot;There is no cloud&quot;&#x2F;&gt;
&lt;h2 id=&quot;more-on-this-topic&quot;&gt;More on this topic&lt;&#x2F;h2&gt;
&lt;p&gt;Congratulations, you made it to the end. I hope you learned something, if you enjoyed this piece, you can read my post about &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;&quot;&gt;how I&#x27;m helping save lives in West Africa using free software&lt;&#x2F;a&gt;, or you can &lt;em&gt;like, share and subscribe; it helps fight the algorithm.&lt;&#x2F;em&gt; Here are some links you may find interesing:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=uaflChh3n1A&quot;&gt;Introduction to AWS&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;xkcd.com&#x2F;908&#x2F;&quot;&gt;The Cloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=MQbkN99eBD8&quot;&gt;Why is Kubernetes everywhere?&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;basecamp.com&#x2F;cloud-exit&quot;&gt;We left the cloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=vBjonut1JMk&quot;&gt;How Kubernetes is built&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=tCehFMwjWqM&quot;&gt;AI won&#x27;t take your job (but this will)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=CjKhQoYeR4Q&quot;&gt;Getting started with AWS, step by step guide&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Syndromic Surveillance! (Part 1)</title>
        <published>2025-08-24T00:00:00+00:00</published>
        <updated>2025-08-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/syndromic-surveillance/"/>
        <id>https://nskm.xyz/posts/syndromic-surveillance/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/syndromic-surveillance/">  &lt;img style=&quot;display: block; margin: 0 auto; width: 600px&quot; src=&quot;&#x2F;images&#x2F;surveillance_screens.jpg&quot; alt=&quot;&quot; title=&quot;Liberty&quot;&#x2F;&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h2 id=&quot;disclaimers&quot;&gt;Disclaimers :&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Opinions expressed in this post &lt;em&gt;(and in any of all my posts)&lt;&#x2F;em&gt; are solely, &lt;em&gt;unless otherwise specified&lt;&#x2F;em&gt;, those of the authors, &lt;em&gt;me&lt;&#x2F;em&gt;. Those opinions absolutely do not reflect the views, policies, positions of any organizations, employers, affiliated groups.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I&#x27;ve strived for accuracy throughout this piece, but if you catch any errors, please reach out—I&#x27;d be grateful for the feedback and happy to make updates!&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h2 id=&quot;toc&quot;&gt;TOC:&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#hook&quot;&gt;Hook&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#history&quot;&gt;Definition, context, history&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#what&quot;&gt;4S overview&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#core&quot;&gt;Core principles&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#collect&quot;&gt;Data collection&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#process&quot;&gt;Data processing and storage&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#share&quot;&gt;Data sharing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#alert&quot;&gt;Alerting and notifications&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#integration&quot;&gt;Integration with existing systems&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#stack&quot;&gt;The technological stack&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#front&quot;&gt;Frontend&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#back&quot;&gt;Backend&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#else&quot;&gt;More&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#engineers&quot;&gt;The engineering team&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#future&quot;&gt;The roadmap&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;syndromic-surveillance&#x2F;#more&quot;&gt;More on this topic&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h2 id=&quot;hook&quot;&gt;&lt;u&gt;Hook:&lt;&#x2F;u&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;From &lt;strong&gt;June 30 to July 2, 2025&lt;&#x2F;strong&gt;, a coordination meeting for the entire 4S network was recently held in &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Lom%C3%A9&quot;&gt;Lomé, Togo&lt;&#x2F;a&gt;. During this meeting, a new implementation of the &lt;strong&gt;4S platform&lt;&#x2F;strong&gt; was presented to the participants.&lt;&#x2F;p&gt;
&lt;video style=&quot;display: block; margin: 0 auto; width: 600px&quot; class=&quot;video&quot; controls=&quot;controls&quot; &gt;
  &lt;source  src=&quot;&#x2F;images&#x2F;4s-annual-regional-coordination-meeting.mp4&quot; type=&quot;video&#x2F;mp4&quot; &#x2F;&gt;
  Your browser does not support the video tag.
&lt;&#x2F;video&gt;
&lt;p&gt;Quote:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Le réseau 4S a été conçu pour répondre à un besoin crucial, celui de disposer d&#x27;un système régional de surveillance capable de détecter précocément les maladies de santé publique, de renforcer les capacités de laboratoires et de partager des données pour une réponse adéquate et adaptée aux problèmes sanitaires.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Quote :&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The 4S network was designed to meet a crucial need: to have a regional surveillance system capable of early detection of public health diseases, strengthening laboratory capacities and sharing data for an adequate and appropriate response to health issues.
&lt;br&gt;
&lt;br&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The striking disconnect that exists across many sectors, public health included. Officials excel at announcing initiatives and securing funding. Press releases about &lt;em&gt;&quot;implementing advanced early detection systems&quot;&lt;&#x2F;em&gt; generate buzz and demonstrate progress. But when it comes to the unglamorous technical work: database design, API development, system integration... Silence. These crucial implementation details, handled by &lt;em&gt;anonymous engineers and developers&lt;&#x2F;em&gt;, rarely see daylight in public discourse.&lt;&#x2F;p&gt;
&lt;p&gt;While policy makers avoid technical specifics, it&#x27;s precisely these software choices that determine whether systems function during critical moments.&lt;&#x2F;p&gt;
&lt;br&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 250px&quot; src=&quot;&#x2F;images&#x2F;mother.jpg&quot; alt=&quot;Mother&quot; title=&quot;Mother&quot;&#x2F;&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h2 id=&quot;history&quot;&gt;&lt;u&gt;Definition, context, history:&lt;&#x2F;u&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;A syndromic surveillance system is a &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Y6DPDC_Mf90&quot;&gt;public health&lt;&#x2F;a&gt; &lt;strong&gt;surveillance&lt;&#x2F;strong&gt; system that monitors &lt;strong&gt;symptom clusters&lt;&#x2F;strong&gt; rather than specific confirmed diagnoses. It aims to &lt;strong&gt;detect epidemics or public health events&lt;&#x2F;strong&gt; at an &lt;strong&gt;early&lt;&#x2F;strong&gt; stage, by analyzing data in real time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2007&quot;&gt;2007:&lt;&#x2F;h3&gt;
&lt;p&gt;Before 2007, &lt;a href=&quot;https:&#x2F;&#x2F;simple.wikipedia.org&#x2F;wiki&#x2F;Madagascar&quot;&gt;Madagascar&lt;&#x2F;a&gt; only had a passive, monthly paper-based reporting system that was &lt;em&gt;&lt;strong&gt;too slow&lt;&#x2F;strong&gt;&lt;&#x2F;em&gt; for outbreak response. The &lt;em&gt;&lt;a href=&quot;https:&#x2F;&#x2F;pubmed.ncbi.nlm.nih.gov&#x2F;17505252&#x2F;&quot;&gt;chikungunya outbreak&lt;&#x2F;a&gt;&lt;&#x2F;em&gt; in the Indian Ocean exposed &lt;em&gt;&lt;strong&gt;critical gaps&lt;&#x2F;strong&gt;&lt;&#x2F;em&gt; in Madagascar&#x27;s disease surveillance.&lt;&#x2F;p&gt;
&lt;p&gt;The solution was to setup a real-time sentinel surveillance system using mobile phones for daily data transmission. This implementation was &lt;em&gt;&lt;strong&gt;the first nationwide real-time-like&lt;&#x2F;strong&gt;&lt;&#x2F;em&gt; &lt;a href=&quot;https:&#x2F;&#x2F;pdfs.semanticscholar.org&#x2F;66b8&#x2F;8be85954b548c3b744ffd7ea8bac7ccae008.pdf&quot;&gt;surveillance system&lt;&#x2F;a&gt; ever established in Madagascar.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2012&quot;&gt;2012:&lt;&#x2F;h3&gt;
&lt;p&gt;The Syndromic Sentinel Surveillance System in Senegal, the 4S network, is &lt;a href=&quot;https:&#x2F;&#x2F;rh.pasteur.sn&#x2F;en&#x2F;research-and-public-health&#x2F;epidemiology-clinical-research-and-data-science&#x2F;fever-surveillance-syndromic-sentinel-surveillance-senegal-4s-network&quot;&gt;Another syndromic sentinel surveillance system&lt;&#x2F;a&gt; based on febrile syndromes. It was implemented in Senegal in 2012 and inpired by the Madagascar model.&lt;&#x2F;p&gt;
&lt;p&gt;The criteria of individual target diseases are based on &lt;a href=&quot;https:&#x2F;&#x2F;www.who.int&#x2F;publications&#x2F;i&#x2F;item&#x2F;who-recommended-surveillance-standards&quot;&gt;World Health Organization recommended surveillance standards&lt;&#x2F;a&gt;. This means: for &lt;em&gt;each disease&lt;&#x2F;em&gt; or &lt;em&gt;syndrome&lt;&#x2F;em&gt; there is a description of the &lt;em&gt;rationale for surveillance, case definition, types of surveillance, minimum data elements, data analyses and principal uses of data for decision-making.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Data are transmitted on a daily basis by the general practitioners of the sentinel sites. They are validated and analyzed daily within the epidemiology unit of the Institution. These data are sent to the Ministry of Health in the form of a weekly newsletter.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2015&quot;&gt;2015:&lt;&#x2F;h3&gt;
&lt;p&gt;The existing implementation faced significant challenges. The database consisted of scattered Excel files distributed across multiple locations, making studies and analyses complicated and time-consuming. There was an urgent need to organize, structure, and centralize these disparate files.&lt;&#x2F;p&gt;
&lt;p&gt;To address these issues, a new platform was developed: Teranga. Built using &lt;a href=&quot;https:&#x2F;&#x2F;httpd.apache.org&#x2F;&quot;&gt;Apache&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.php.net&#x2F;&quot;&gt;PHP&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;JavaScript&quot;&gt;Javascript&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;www.mysql.com&#x2F;products&#x2F;community&#x2F;&quot;&gt;MySQL&lt;&#x2F;a&gt;, Teranga provides improved data management, enhanced tracking capabilities, modular architecture, and streamlined deployment during outbreak situations.&lt;&#x2F;p&gt;
&lt;p&gt;The new sentinel surveillance system included 17 health centers and &lt;a href=&quot;https:&#x2F;&#x2F;www.omicsonline.org&#x2F;proceedings&#x2F;early-outbreak-detection-through-sentinel-surveillance-system-in-senegal-51640.html&quot;&gt;identified 4 confirmed outbreaks&lt;&#x2F;a&gt;. The system has proved the feasibility of improving disease surveillance capacity through innovative technological solutions.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2020&quot;&gt;2020:&lt;&#x2F;h3&gt;
&lt;p&gt;When &lt;a href=&quot;https:&#x2F;&#x2F;www.cdc.gov&#x2F;covid&#x2F;about&#x2F;index.html&quot;&gt;COVID-19&lt;&#x2F;a&gt; struck, Teranga rose to meet an unprecedented challenge, becoming the backbone of Senegal&#x27;s pandemic response. Seamlessly coordinating patient care, traveler monitoring, financial operations, clinical research, and treatment center management across the entire country. The pandemic trully elevated Teranga to a mission-critical status.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2022&quot;&gt;2022:&lt;&#x2F;h3&gt;
&lt;p&gt;What began as a surveillance system for on institution, evolved to become West Africa indispensable healthcare hub: The 4S network. Teranga is now expanding from Senegal into other West African countries: Gambia, Cape-Verde, Mauritania, Niger, Mali, Togo, Guinea, Guinea Bissau, Sierra-Leone and Benin. The goal being to provide broader coverage and improve health systems in a sustainable and effective manner.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2023&quot;&gt;2023:&lt;&#x2F;h3&gt;
&lt;p&gt;I am hired by the Institution. I&#x27;m tasked with reimplementing the current system, rebuilding it from scratch while improving on what came before. I don&#x27;t have much say in the tech stack, just enough &lt;em&gt;freedom&lt;&#x2F;em&gt; to go with what works for &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;toolbelt&#x2F;&quot;&gt;me&lt;&#x2F;a&gt;. The usual lineup of &lt;a href=&quot;https:&#x2F;&#x2F;www.debian.org&#x2F;&quot;&gt;Debian&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.python.org&#x2F;&quot;&gt;Python&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;djangoproject.com&#x2F;&quot;&gt;Django&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.postgresql.org&#x2F;&quot;&gt;Postgresql&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.nginx.org&#x2F;&quot;&gt;Nginx&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;podman.io&quot;&gt;Podman&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;&quot;&gt;Git&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;&quot;&gt;Gitlab&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;emacs&#x2F;&quot;&gt;Emacs&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;tmuxcheatsheet.com&#x2F;&quot;&gt;Tmux&lt;&#x2F;a&gt;, etc ... More on that in the following episodes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2025&quot;&gt;2025:&lt;&#x2F;h3&gt;
&lt;p&gt;The surveillance platform my colleagues and I have spent two years developing has now been presented to the public. But public recognition &lt;a href=&quot;https:&#x2F;&#x2F;c.tenor.com&#x2F;vLK4Mq3jiKIAAAAC&#x2F;tenor.gif&quot;&gt;is not really the source of my pride&lt;&#x2F;a&gt;. What matters is that our system, our algorithms, our data structures, our functions, our for loops, our SQL queries are actively making a difference in saving lives. Phew!&lt;&#x2F;p&gt;
&lt;br&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 250px&quot; src=&quot;&#x2F;images&#x2F;wip.jpg&quot; alt=&quot;Work in progress&quot; title=&quot;Work in progress...&quot;&#x2F;&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h2 id=&quot;what&quot;&gt;&lt;u&gt;4S overview:&lt;&#x2F;u&gt;&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;identify unusual health events earlier and provide a quicker response.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I can&#x27;t say it better.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;core&quot;&gt;Core principles:&lt;&#x2F;h3&gt;
&lt;p&gt;It&#x27;s really fascinating that these early systems already recognized the core principles we are trying to implement today:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;collect&quot;&gt;1. Standardized data collection:&lt;&#x2F;h4&gt;
&lt;p&gt;Healthcare providers at sentinel sites should use standardized digital forms to capture essential demographic, clinical, and temporal information. We want to ensure consistency across all participating facilities and enable accurate epidemiological analysis. We should always try to adhere to WHO surveillance standards with clearly predefined entities &amp;amp; attributes.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;process&quot;&gt;2. Data processing and storage:&lt;&#x2F;h4&gt;
&lt;p&gt;The platform should handles real-time data streaming between microservices, enabling immediate processing of incoming surveillance data. Each microservice should ensures data integrity through automated validation rules. We should always check for completeness, consistency, and quality. Validated data should be stored in a database with proper indexing for efficient retrieval.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;share&quot;&gt;3. Information sharing:&lt;&#x2F;h4&gt;
&lt;p&gt;The epidemiology unit generates documents consolidating validated surveillance data for the Ministry of Health. The platform integrates with third parties to share aggregated data with the Ministry of Health. The platform also provides interactive dashboards for stakeholders.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;alert&quot;&gt;4. Alerting and notifications:&lt;&#x2F;h4&gt;
&lt;p&gt;The platform should ensure immediate notification delivery to relevant actor via email and dashboard notifications. Whenever needed, the platform should automatically generates notifications through multiple channels—email alerts, in-app notifications, and dashboard warnings.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;integration&quot;&gt;5. Integration with existing systems:&lt;&#x2F;h4&gt;
&lt;p&gt;The platform should seamlessly integrate with the regional health data aggregation system and any other existing platform used by Ministry of Health. The system must also integrate easily with any biobank systems that may exist.
&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;A drawing is worth more than thousand words:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;text&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-text &quot;&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&lt;span&gt;                                    [Health facility]   [Hospital]         [Clinic]
&lt;&#x2F;span&gt;&lt;span&gt;                                          |                 |                  |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |                 |                  |
&lt;&#x2F;span&gt;&lt;span&gt;                                     ┌────┴─────────────────┴──────────────────┴──────┐
&lt;&#x2F;span&gt;&lt;span&gt;                                     │                4S platform                     │
&lt;&#x2F;span&gt;&lt;span&gt;                                     │     • Data collection (Patients, symptoms, ...)│
&lt;&#x2F;span&gt;&lt;span&gt;                                     │     • Data validation &amp;amp; storage                │
&lt;&#x2F;span&gt;&lt;span&gt;                                     │     • Data treatment (Analyses, studies, ...)  │
&lt;&#x2F;span&gt;&lt;span&gt;                                     │     • Data sharing (Reports, alerts, ...)      │
&lt;&#x2F;span&gt;&lt;span&gt;                                     │     • Data dashboards (Statistics, plots, ...) │
&lt;&#x2F;span&gt;&lt;span&gt;                                     └────┬──────────────────┬──────────────┬─────────┘
&lt;&#x2F;span&gt;&lt;span&gt;                                          |                  |              |
&lt;&#x2F;span&gt;&lt;span&gt;                                     ┌────┴────┐             |         ┌────┴────┐
&lt;&#x2F;span&gt;&lt;span&gt;                                     │ Reports │             |         │ Alerts  │
&lt;&#x2F;span&gt;&lt;span&gt;                                     │Analytics│             |         │Warnings │
&lt;&#x2F;span&gt;&lt;span&gt;                                     └────┬────┘             |         └────┬────┘
&lt;&#x2F;span&gt;&lt;span&gt;                                          |                  |              |
&lt;&#x2F;span&gt;&lt;span&gt;                                          |                  |              |
&lt;&#x2F;span&gt;&lt;span&gt;                                     [Public Health]    [Research] [Emergency Response]
&lt;&#x2F;span&gt;&lt;span&gt;                                       Department
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is the platform we are trying to build :) I can stop the post here, thanks for reading ...&lt;&#x2F;p&gt;
&lt;h3 id=&quot;stack&quot;&gt;The technological stack:&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;front&quot;&gt;Frontend:&lt;&#x2F;h4&gt;
&lt;p&gt;The 4S platform frontend leverages &lt;a href=&quot;https:&#x2F;&#x2F;angularjs.dev&#x2F;&quot;&gt;AngularJS&lt;&#x2F;a&gt; with &lt;a href=&quot;https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;&quot;&gt;TypeScript&lt;&#x2F;a&gt;, providing a dynamic and type-safe user interface that ensures smooth interactions for healthcare providers.&lt;&#x2F;p&gt;
&lt;p&gt;One of the main component of our architecture is &lt;a href=&quot;https:&#x2F;&#x2F;www.keycloak.org&#x2F;&quot;&gt;Keycloak&lt;&#x2F;a&gt;, an identity &amp;amp; access management solution that handles user authentication, authorization accross the entire platform. Customizing the Django Rest Framework&#x27;s authentication classes to handle different tokens sent by different realms was an adventure worthy of an article.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;back&quot;&gt;Backend:&lt;&#x2F;h4&gt;
&lt;p&gt;The backend infrastructure centers around &lt;a href=&quot;https:&#x2F;&#x2F;python.org&quot;&gt;Python&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;djangoproject.com&quot;&gt;Django&lt;&#x2F;a&gt;, and Django Rest Framework. With each passing day, as we make progress on the project, I become more and more convinced that it was the right choice. Django is an amazing piece of software, thanks a lot to all its contributors.&lt;&#x2F;p&gt;
&lt;p&gt;Data management is handled by &lt;a href=&quot;https:&#x2F;&#x2F;www.postgresql.org&quot;&gt;PostgreSQL&lt;&#x2F;a&gt;, our primary database system. I can proudly say that I&#x27;m the one who made this choice. Postgresql is known for its reliability, strong adherence to SQL standards, powerful extensibility, support for complex data types, ACID compliance, robust security features, and excellent community support.&lt;&#x2F;p&gt;
&lt;p&gt;To handle real-time communication and event-driven processes such as email notifications, lab result updates, and system alerts, we&#x27;ve integrated &lt;a href=&quot;https:&#x2F;&#x2F;kafka.apache.org&#x2F;&quot;&gt;Apache Kafka&lt;&#x2F;a&gt;. Kafka ensures that critical healthcare information flows efficiently between different system components without data loss.&lt;&#x2F;p&gt;
&lt;p&gt;In order to detect outbreaks, samples (blood, urine, stool, etc.) must be collected. And to effectively manage vast biological sample collections, ensure data integrity, and streamline complex workflows, we need a Biobank and a Biobanking software. A biobank is essentially an organized library of biological samples (like blood and tissue) that are stored alongside health and personal information, all used to support medical research. &lt;a href=&quot;https:&#x2F;&#x2F;www.modul-bio.com&#x2F;en&#x2F;our-solutions&#x2F;mbiolims&#x2F;&quot;&gt;Mbiolims&lt;&#x2F;a&gt; is the biobanking software we use to manage our samples and their associated data.&lt;&#x2F;p&gt;
&lt;p&gt;Here too, I would need to write a really long article telling you how we&#x27;ve managed to do the integration between Django and MBioLIMS :) Hehe!&lt;&#x2F;p&gt;
&lt;h4 id=&quot;ops&quot;&gt;Operations:&lt;&#x2F;h4&gt;
&lt;p&gt;All code versioning and collaboration is managed through &lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; &amp;amp; Bitbucket, ensuring secure source code management, proper access controls and audit trails. While Bitbucket provides comprehensive version control and collaboration features, I&#x27;m still convinced it was not the right choice. &lt;a href=&quot;https:&#x2F;&#x2F;about.gitlab.com&#x2F;&quot;&gt;Gitlab&lt;&#x2F;a&gt; ? &lt;a href=&quot;https:&#x2F;&#x2F;about.gitea.com&#x2F;&quot;&gt;Gitea&lt;&#x2F;a&gt; ? Github ? Come on!&lt;&#x2F;p&gt;
&lt;p&gt;The 4S platform is in fact a constallation of multiple running containers. Those containers are built using Docker and &lt;a href=&quot;https:&#x2F;&#x2F;podman.io&quot;&gt;Podman&lt;&#x2F;a&gt; technologies, enabling consistent deployment across different environments while simplifying development and testing workflows. I mean, I&#x27;m the only one using Podman while all my teammates are still using Docker :\&lt;&#x2F;p&gt;
&lt;p&gt;Our continuous integration and deployment pipeline is powered by Jenkins. Jenkins automates testing and deployment processes to maintain code quality and enable rapid, reliable updates. I prefer &lt;a href=&quot;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ci&#x2F;&quot;&gt;GitlabCI&lt;&#x2F;a&gt; by 13 parsecs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;&quot;&gt;Kubernetes&lt;&#x2F;a&gt; is used for container orchestration, deployment and operations. K8s provides automatic scaling, load balancing, and high availability to ensure our platform can handle varying loads and maintain uptime. My opinions on this tool are mixed.&lt;&#x2F;p&gt;
&lt;p&gt;In one side, K8s will allow us to easily scale our applications up or down based on demand. This is a critical requirement for managing sensitive healthcare information. In the other side, I live in a part of the world where most medical facilities (most people, let&#x27;s be honest) do not even have a working domain name, website, and email address. How can we ask them for the DevOps expertise to manage a Kubernetes cluster? I will see to what extent I can write an article about Kubernetes.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;else&quot;&gt;Even more:&lt;&#x2F;h4&gt;
&lt;p&gt;There are other essential components of the system which I am not really familiar with.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;dhis2.org&#x2F;&quot;&gt;DHIS2&lt;&#x2F;a&gt; is widely adopted across West Africa for integrated health information systems, disease surveillance, education management, and public health emergency response. We simply cannot ask a country that already uses DHIS2 to use the 4S platform without it being able to transfer data back to a DHIS2 instance.&lt;&#x2F;p&gt;
&lt;p&gt;We have an &lt;a href=&quot;https:&#x2F;&#x2F;superset.apache.org&#x2F;&quot;&gt;Apache Superset&lt;&#x2F;a&gt; instance for data visualization and exploration. With Apache Superset, we can easily let a third party consult some information, without modifying our system.&lt;&#x2F;p&gt;
&lt;p&gt;Our platform generate lots of files, analysis reports &amp;amp; statistics. We needed something to store vast amounts of unstructured data, like images, videos, pdf documents, etc... We choosed &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;minio&#x2F;minio&quot;&gt;MinIO&lt;&#x2F;a&gt; for this use case.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;The diagram we&#x27;ve seen above can also be seen using this different perspective:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;    +-----------------------------------------------------------------------------------------------------------------------+
&lt;&#x2F;span&gt;&lt;span&gt;    |                                                      KUBERNETES CLUSTER                                               |
&lt;&#x2F;span&gt;&lt;span&gt;    +-----------------------------------------------------------------------------------------------------------------------+
&lt;&#x2F;span&gt;&lt;span&gt;    |                                                                                                                       |
&lt;&#x2F;span&gt;&lt;span&gt;    |  +--------------------------------------------------+   &amp;lt;-- (Auth&#x2F;Roles) --&amp;gt;  +------------------+                    |
&lt;&#x2F;span&gt;&lt;span&gt;    |  |             FRONTEND CLIENTS                     |------------------------&amp;gt;|     KEYCLOAK     |                    |
&lt;&#x2F;span&gt;&lt;span&gt;    |  |          (AngularJS + TypeScript)                |&amp;lt;------------------------|   (Auth Server   |                    |
&lt;&#x2F;span&gt;&lt;span&gt;    |  +------------------^-------------------------------+                         +-----^------------+                    |
&lt;&#x2F;span&gt;&lt;span&gt;    |                     |                                                               |                                 |
&lt;&#x2F;span&gt;&lt;span&gt;    |              (API Requests)                                                         | (Auth&#x2F;Roles)                    |
&lt;&#x2F;span&gt;&lt;span&gt;    |                     |                                                          +----+                                 |
&lt;&#x2F;span&gt;&lt;span&gt;    |                     |                                                          |                                      |
&lt;&#x2F;span&gt;&lt;span&gt;    +---------------------v----------------------------------------------------------v--------------------------------------+
&lt;&#x2F;span&gt;&lt;span&gt;    |  +--------------------------------------------------------------------------------+      +--------------------------+ |
&lt;&#x2F;span&gt;&lt;span&gt;    |  |                BACKEND MICROSERVICES (Django Rest Framework)                   |      |    Biobank (Mbiolims)    | |
&lt;&#x2F;span&gt;&lt;span&gt;    |  |      Microservices exchanges data via a message broker (Kafka in our case)     |&amp;lt;----&amp;gt;|   Stores Samples infos   | |
&lt;&#x2F;span&gt;&lt;span&gt;    |  |   [Microservice A]  &amp;lt;--Data--&amp;gt;  [Microservice B] &amp;lt;--Data--&amp;gt; [Microservice N-1] |      |                          | |
&lt;&#x2F;span&gt;&lt;span&gt;    |  +-------------------------^-----------------------^-------------------------^----+      +--------------------------+ |
&lt;&#x2F;span&gt;&lt;span&gt;    |                            |                       |                         |                                        |
&lt;&#x2F;span&gt;&lt;span&gt;    |              (Store&#x2F;Retrieve)       (Write&#x2F;Open Files)      (Sends data aggregations)                                 |
&lt;&#x2F;span&gt;&lt;span&gt;    |                            |                       |                         |                                        |
&lt;&#x2F;span&gt;&lt;span&gt;    +----------------------------v-----------------------v-------------------------v----------------------------------------+
&lt;&#x2F;span&gt;&lt;span&gt;    | +--------------------------------+ +--------------------------------+ +--------------------------------------------+  |
&lt;&#x2F;span&gt;&lt;span&gt;    | |        POSTGRESQL DB           | |             MINIO              | |                   DHIS2                    |  |
&lt;&#x2F;span&gt;&lt;span&gt;    | |     (Primary Data Store)       | |      (Object&#x2F;File Storage)     | |           (External Data Recipient)        |  |
&lt;&#x2F;span&gt;&lt;span&gt;    | +--------------------------------+ +--------------------------------+ +--------------------------------------------+  |
&lt;&#x2F;span&gt;&lt;span&gt;    |               | (Reads Data)                                                                                          |
&lt;&#x2F;span&gt;&lt;span&gt;    |               |                                                                                                       |
&lt;&#x2F;span&gt;&lt;span&gt;    | +-------------v--------------------+                                                                                  |
&lt;&#x2F;span&gt;&lt;span&gt;    | |    APACHE SUPERSET (Dataviz)     |                                                                                  |
&lt;&#x2F;span&gt;&lt;span&gt;    | +----------------------------------+                                                                                  |
&lt;&#x2F;span&gt;&lt;span&gt;    |                                                                                                                       |
&lt;&#x2F;span&gt;&lt;span&gt;    +-----------------------------------------------------------------------------------------------------------------------+
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h3 id=&quot;engineers&quot;&gt;The engineering team:&lt;&#x2F;h3&gt;
&lt;p&gt;This article is also for my fellow developers who built the 4S network under impossible constraints—limited budgets, legacy infrastructure, unrealistic timelines. My colleagues engineers writing scripts to detect disease patterns, configuring servers that never get enough resources. My teammates who&#x27;s written documentation that nobody reads but everyone depends on. I&#x27;m talking about the people who made the story:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;cisse&quot;&gt;Cisse:&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;mamadou-cisse-723b29114&#x2F;&quot;&gt;Cisse&lt;&#x2F;a&gt; a.k.a &quot;Celui qui fait bouger le monde&quot;, plays a crucial role in coordinating activities across the Institution Digital Factory team. His expertise extends to managing and preserving the integrity of biomedical data within the Institution. He works closely with stakeholders to validate specifications of new health applications. To uncover more about him, follow this &lt;a href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;mamadou-cisse-723b29114&#x2F;&quot;&gt;link&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;mame-astou&quot;&gt;Mame Astou:&lt;&#x2F;h4&gt;
&lt;p&gt;As an integral member of the development team, &lt;a href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;mameastougassama&quot;&gt;Mame Astou&lt;&#x2F;a&gt; a.k.a &quot;Madame La Directrice&quot;, craft robust and dynamic web applications while maintaining a keen eye for intuitive user interface design. She knows how to create user experiences that prioritize both aesthetic appeal and seamless usability. What would we be without her? Absolutely nothing. To uncover more about her, please visit this &lt;a href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;mameastougassama&quot;&gt;page&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;diom&quot;&gt;Diom:&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.doyoubuzz.com&#x2F;diom-sow&quot;&gt;Diom&lt;&#x2F;a&gt;, a.k.a &quot;Le Grand Marabout de l&#x27;Architecture&quot;, is a DevOps engineer who bridges the gap between development and operations. With expertise in containerization technologies, cloud platforms, and monitoring solutions, he design and maintain scalable deployment environments while ensuring system reliability and security.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;abdoul-karim&quot;&gt;Abdoul Karim:&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;mohamed-abdoul-karim-diop-76250b127&#x2F;&quot;&gt;Abdoul Karim&lt;&#x2F;a&gt; is probably the pillar of the team, always ready to make concessions and take responsibility. His technical experience spans multiple domains. It would take me hours to explain why he is an excellent engineer. Just go and find out by yourself how great &lt;a href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;mohamed-abdoul-karim-diop-76250b127&#x2F;&quot;&gt;he is&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;mariama&quot;&gt;Mariama:&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a href=&quot;#&quot;&gt;Mariama&lt;&#x2F;a&gt; a.k.a &quot;La Sauveuse De Tous Les Hommes&quot;, has a deep knowledge of Scrum and agile principles. She guide the team through iterative development cycles while fostering continuous improvement and team collaboration. We are still waiting for that one day she will finally write a few lines of TypeScript. Access Mariama&#x27;s comprehensive profile by following this &lt;a href=&quot;#&quot;&gt;link&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;birante&quot;&gt;Birante:&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;fr.linkedin.com&#x2F;in&#x2F;birantesy&quot;&gt;Birante&lt;&#x2F;a&gt; has an exceptional expertise that encompasses everything from custom UI animations and state management to integrating native device features and third-party services. He is able to deliver native-quality experiences across both iOS, Android and Web platforms. He secretly dreams about rewriting all the 4s platform using &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=gcwzWzC7gUA&quot;&gt;RoR&lt;&#x2F;a&gt; applications. Here is a &lt;a href=&quot;#&quot;&gt;link&lt;&#x2F;a&gt; to get the complete picture about Birante.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;tidiane&quot;&gt;Tidiane:&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;adtidiane&quot;&gt;Tidiane&lt;&#x2F;a&gt;, a.k.a &quot;Le Sage&quot;, a.k.a &quot;The Biobank expert&quot;, is probably the wisest and most reserved member of the team. Tidiane is a seasoned backend developer who brings deep expertise in Django framework development. He excel at designing robust APIs and implementing complex business logic that powers modern web applications. If you know anyone who works at &lt;a href=&quot;https:&#x2F;&#x2F;www.modul-bio.com&quot;&gt;Mbiolims&lt;&#x2F;a&gt;, please tell them they should hire Tidiane. His background can be found &lt;a href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;amadou-tidiane-diallo-61065a41&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;adrien&quot;&gt;Adrien:&lt;&#x2F;h4&gt;
&lt;p&gt;Aux âmes bien nées, la valeur n&#x27;attend point le nombre d&#x27;années. &lt;a href=&quot;#&quot;&gt;Adrien&lt;&#x2F;a&gt;, the youngest in the team, is a software engineer with an extensive experience in developing RESTful APIs, managing database migrations, and implementing automated testing frameworks within Django projects. For additional information about Adrien, visit this &lt;a href=&quot;#&quot;&gt;link&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Guys, your dedication, your resilience, your ingenuity deserve recognition far beyond what they receive.
Thank you.&lt;&#x2F;strong&gt;
&lt;br&gt;
&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;future&quot;&gt;The roadmap:&lt;&#x2F;h3&gt;
&lt;p&gt;Right now we&#x27;re developing comprehensive features related to &lt;strong&gt;&quot;case management&quot;&lt;&#x2F;strong&gt;. Those features will enable healthcare providers to track patient journeys from initial consultation through treatment completion, ensuring continuity of care and improved outcomes.&lt;&#x2F;p&gt;
&lt;p&gt;We plan to extend our platform to handle a &lt;strong&gt;wider spectrum of medical conditions and syndromes&lt;&#x2F;strong&gt;, transforming it from a specialized tool into a comprehensive healthcare management solution.&lt;&#x2F;p&gt;
&lt;p&gt;Our platform will also align with the &lt;strong&gt;One Health approach&lt;&#x2F;strong&gt;, recognizing the interconnection between human, animal, and environmental health.&lt;&#x2F;p&gt;
&lt;p&gt;Data exchange with other healthcare systems, electronic health records, and medical devices, is something we need to work towards. We really need to meet evolving healthcare standards and prepare for international expansion. While I agree we didn&#x27;t put enough efforts on this, compliance and interoperability remain central to our development strategy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;more&quot;&gt;&lt;u&gt;More on the topic:&lt;&#x2F;u&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Writing about 4S implementation could fill volumes. For those ready to dig deeper into the technical and policy dimensions of public health surveillance, &lt;em&gt;and before I write the second part of this series&lt;&#x2F;em&gt;, here are resources that expand on the key concepts discussed:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;healthsites-io&#x2F;cartographie-des-donn%C3%A9es-sanitaires-durgence-au-s%C3%A9n%C3%A9gal-474c3c3bec29&quot;&gt;Mapping emergency health data in Senegal&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Z8pa6BQN54w&quot;&gt;How CARE transforms outbreaks into opportunities for Africa&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=cZfzP3J2VxY&quot;&gt;A new way to fight infectious diseases and predict outbreaks&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;stories.theglobalfund.org&#x2F;early-detection-for-rapid-response-strengthening-disease-surveillance-across-west-africa&quot;&gt;Early detection for rapid response: strengthening disease surveillance across West Africa&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;institutpasteurdakar.sn&#x2F;strengthening-epidemic-resilience-through-one-health-and-integrated-community-based-surveillance&#x2F;&quot;&gt;Strengthening epidemic resilience through one health and integrated community-based surveillance&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.kaikai.dev&#x2F;blog&#x2F;blog-1&#x2F;ihe-for-senegal-a-look-back-at-the-ihe-training-week-6&quot;&gt;Launch and training on medical data exchange in Senegal according to IHE standards&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=pmiQza2kQmE&quot;&gt;Dengue sylvatique : l’angle mort du diagnostic — Dr Idrissa Dieng&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Some people we might want to collaborate with:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;data.humdata.org&#x2F;&quot;&gt;the Humanitarian Data Exchange&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;healthsites.io&#x2F;&quot;&gt;HealthSites.IO, I&#x27;ve contributed Python code for them&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;eyone.net&#x2F;en&#x2F;about-us&quot;&gt;Eyone, improving the quality of medical care through technology.&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;njureel.com&#x2F;#accueil&quot;&gt;Njureel,  reinventing the proximity between healthcare professionals and patients&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.geomatica.space&#x2F;&quot;&gt;Geomatica, one of the greatest company in geospatial data (The founder is a very good friend)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I hope you learned something. If you found this article interesting, please share it &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=K0HSD_i2DvA&quot;&gt;around the world&lt;&#x2F;a&gt;. Tell them there are people here who save lives with free and open source software.&lt;&#x2F;p&gt;
&lt;br&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 250px&quot; src=&quot;&#x2F;images&#x2F;sample.jpg&quot; alt=&quot;&quot; title=&quot;Sample container&quot;&#x2F;&gt;
&lt;br&gt;
&lt;br&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Free and Open Source Software.... Again!</title>
        <published>2025-05-31T00:00:00+00:00</published>
        <updated>2025-05-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/fossa/"/>
        <id>https://nskm.xyz/posts/fossa/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/fossa/">  &lt;img style=&quot;display: block; margin: 0 auto; width: 400px&quot; src=&quot;&#x2F;images&#x2F;liberty.jpg&quot; alt=&quot;&quot; title=&quot;Liberty&quot;&#x2F;&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h1 id=&quot;table-of-content&quot;&gt;Table Of Content:&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;fossa&#x2F;#1&quot;&gt;1 Intro &lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;fossa&#x2F;#4&quot;&gt;2. Why contribute&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;fossa&#x2F;#13&quot;&gt;3. Skepticism&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;fossa&#x2F;#14&quot;&gt;4. How to contribute&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;fossa&#x2F;#15&quot;&gt;5. Success stories&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;fossa&#x2F;#16&quot;&gt;6. More on the topic&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;1&quot;&gt;Intro&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;m tired of seeing that the majority of Africans still don&#x27;t &lt;a href=&quot;#&quot;&gt;get it&lt;&#x2F;a&gt;, and probably never will, that free and open source software represents the optimal path forward for our continent. &lt;a href=&quot;https:&#x2F;&#x2F;roylab.xyz&#x2F;&quot;&gt;One of&lt;&#x2F;a&gt; my brightest students asked me to talk about free and open source software, and gave me 2 hours to do so. For him, for Africa, for the future, &lt;a href=&quot;https:&#x2F;&#x2F;c.tenor.com&#x2F;h2M4FDyKANQAAAAC&#x2F;tenor.gif&quot;&gt;here I am&lt;&#x2F;a&gt;...&lt;&#x2F;p&gt;
&lt;p&gt;IT&#x27;s been almost 20 years I see myself as a &lt;a href=&quot;https:&#x2F;&#x2F;lwn.net&#x2F;SubscriberLink&#x2F;1023299&#x2F;7ba649b1ede41895&#x2F;&quot;&gt;free software&lt;&#x2F;a&gt; advocate, therefore my perspectives are inherently biased. Hopefully, the bias is not huge. Let&#x27;s cue the &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=UAs9-VL66vo&quot;&gt;music&lt;&#x2F;a&gt; please!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2&quot;&gt;&lt;ins&gt;&lt;em&gt;Free software:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;The Free software movement, as defined by the &lt;a href=&quot;https:&#x2F;&#x2F;www.fsf.org&#x2F;&quot;&gt;Free Software Foundation&lt;&#x2F;a&gt;, is a social&#x2F;political movement about freedom, ethics, and user rights&#x2F;freedoms. Richard Stallman created the movement in 1983 and the &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;philosophy&#x2F;free-sw.html#four-freedoms&quot;&gt;4 essential user freedoms are&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Freedom to run the program for any purpose&lt;&#x2F;li&gt;
&lt;li&gt;Freedom to study how the program works and change it&lt;&#x2F;li&gt;
&lt;li&gt;Freedom to redistribute copies to help others&lt;&#x2F;li&gt;
&lt;li&gt;Freedom to distribute modified versions to benefit the community&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;3&quot;&gt;&lt;ins&gt;&lt;em&gt;Open source software:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;The term &quot;open source&quot; was coined to rebrand free software with a business-friendly focus. It emphasizes practical benefits like better quality, reliability, and development methodology rather than ethical considerations. Bruce Perens created the &lt;a href=&quot;https:&#x2F;&#x2F;opensource.org&#x2F;&quot;&gt;Open Source Initiative&lt;&#x2F;a&gt; in 1998 and Open source criteria include:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Source code must be available&lt;&#x2F;li&gt;
&lt;li&gt;Free redistribution&lt;&#x2F;li&gt;
&lt;li&gt;Derived works allowed&lt;&#x2F;li&gt;
&lt;li&gt;No discrimination against groups or fields of use&lt;&#x2F;li&gt;
&lt;li&gt;License must not restrict other software&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If we read these &lt;em&gt;two definitions&lt;&#x2F;em&gt; calmly, we can see that there is a very important nuance that should be made here: &lt;strong&gt;the user freedom and independence&lt;&#x2F;strong&gt; is at the center of everything for a free software advocate. This is not necessarily the case for an open source advocate.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;4&quot;&gt;Why contribute:&lt;&#x2F;h2&gt;
&lt;p&gt;Here are compelling reasons why African people should fully embrace Free and Open Source software :&lt;&#x2F;p&gt;
&lt;h3 id=&quot;5&quot;&gt;&lt;ins&gt;&lt;em&gt;Learning:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Free and Open Source Software often attract talented developers. When your code get reviewed by maintainers at companies around the globe, you receive mentorship that money can&#x27;t buy. You&#x27;ll encounter diverse codebases, architectural patterns, problem-solving approaches that you might never see in your day job. Free and Open Source Software forces you to read and understand existing code, which dramatically improves your development skills.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;6&quot;&gt;&lt;ins&gt;&lt;em&gt;Economic opportunities:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Open source contributions can help you land jobs or consulting opportunities. There are many companies worldwide are actively seeking talents. Open source provides the perfect &lt;a href=&quot;https:&#x2F;&#x2F;www.wearedevelopers.com&#x2F;world-congress&#x2F;github-open-source-spotlight&quot;&gt;showcase&lt;&#x2F;a&gt; of your &lt;a href=&quot;https:&#x2F;&#x2F;events.linuxfoundation.org&#x2F;open-source-summit-europe&#x2F;&quot;&gt;abilities&lt;&#x2F;a&gt;. Open source software is often the most accessible option for people with limited budgets. There are a lot of startups across the Black Continent that rely on free and open source solutions to build their digital infrastructure.&lt;&#x2F;p&gt;
&lt;p&gt;We often talk about &lt;a href=&quot;https:&#x2F;&#x2F;www.redhat.com&#x2F;en&#x2F;about&#x2F;development-model&quot;&gt;RedHat&lt;&#x2F;a&gt;, but there are many other companies like: &lt;a href=&quot;https:&#x2F;&#x2F;www.zdnet.com&#x2F;article&#x2F;open-source-is-getting-bigger-and-richer-says-suse&#x2F;&quot;&gt;Suse&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;about.gitlab.com&#x2F;blog&#x2F;monetizing-and-being-open-source&#x2F;&quot;&gt;Gitlab&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=13774420&quot;&gt;Docker&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;nextcloud.com&#x2F;about&#x2F;&quot;&gt;NextCloud&lt;&#x2F;a&gt;, companies that demonstrate various and successful approaches built on free and open source foundations.&lt;&#x2F;p&gt;
&lt;p&gt;In a nutshell, those companies will offer subscriptions and services for a guaranteed support, security updates, patches, custom implementations, customizations, optimizations, trainings, certifications, consulting, ...&lt;&#x2F;p&gt;
&lt;p&gt;I would like to do a special mention for 2 companies: &lt;a href=&quot;https:&#x2F;&#x2F;www.entrouvert.com&#x2F;expertise&#x2F;logiciels-reellement-libres&#x2F;&quot;&gt;Entr&#x27;Ouvert&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;www.logilab.fr&#x2F;societe&quot;&gt;Logilab&lt;&#x2F;a&gt;. They offer implementations, customizations, trainings, and consulting services exclusively with free software, you can see it &lt;a href=&quot;https:&#x2F;&#x2F;dev.entrouvert.org&#x2F;&quot;&gt;here&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;explore&quot;&gt;there&lt;&#x2F;a&gt;. They have a deep expertise in the free software industry and this expertise became a valuable service to their clients. Also, I have very good friends over there, shoutout o&#x2F;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;7&quot;&gt;&lt;ins&gt;&lt;em&gt;Breaking geographic barriers:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Thanks to Free and Open Source Software, your code quality matters more than your location or background. African developers can showcase their skills on the same &lt;a href=&quot;https:&#x2F;&#x2F;github.com&quot;&gt;platforms&lt;&#x2F;a&gt; as Silicon Valley engineers. Free and Open Source is our opportunity for challenging stereotypes and demonstrating our technical talent to the world.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;78&quot;&gt;&lt;ins&gt;&lt;em&gt;Gaming:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Linux was once held back by its compatibility with PC games, but thanks to &lt;a href=&quot;https:&#x2F;&#x2F;www.valvesoftware.com&quot;&gt;Valve&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;store.steampowered.com&#x2F;steamos&#x2F;&quot;&gt;SteamOS&lt;&#x2F;a&gt;, those days are in the past. Better gaming performance, better battery life, better power management, are &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=CJXp3UYj50Q&quot;&gt;another reasons&lt;&#x2F;a&gt; to use Linux.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;8&quot;&gt;&lt;ins&gt;&lt;em&gt;Community:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;The open source community represents humanity at its best, a global network where people freely exchange expertise and genuinely celebrate one another&#x27;s wins. When you realize your contribution has solved someone&#x27;s problem or saved them hours of work, that feeling is pure gold. Belonging to a community, building &lt;a href=&quot;https:&#x2F;&#x2F;www.thesocialcreatures.org&#x2F;thecreaturetimes&#x2F;evolution-of-social-connection&quot;&gt;social connections&lt;&#x2F;a&gt; is essential to our wellbeing, it is as important as food, water and shelter.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;9&quot;&gt;&lt;ins&gt;&lt;em&gt;Digital sovereignty:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;2307.01791&quot;&gt;Digital sovereignty&lt;&#x2F;a&gt; encompasses control over critical digital infrastructure like internet networks, data centers, communication systems and mobile&#x2F;web platforms. Digital sovereignty is the ability to regulate how &lt;em&gt;our&lt;&#x2F;em&gt; data is collected, stored, and processed within &lt;em&gt;our&lt;&#x2F;em&gt; jurisdiction.&lt;&#x2F;p&gt;
&lt;p&gt;What happens when a country&#x27;s government systems, banking infrastructure, or communication networks depend entirely on software and services controlled by foreign companies. This is where free and open source software becomes crucial for digital sovereignty.&lt;&#x2F;p&gt;
&lt;p&gt;When you use non free and non open source software:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;you&#x27;re dependent on the vendor&#x27;s decisions, pricing, and continued support.&lt;&#x2F;li&gt;
&lt;li&gt;you can&#x27;t see how it works, modify it for your needs, or ensure it doesn&#x27;t contain &lt;a href=&quot;https:&#x2F;&#x2F;cyberlaw.ccdcoe.org&#x2F;wiki&#x2F;African_Union_headquarters_hack_(2018)&quot;&gt;backdoors&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;you &lt;a href=&quot;https:&#x2F;&#x2F;www.dw.com&#x2F;en&#x2F;will-meta-lawsuits-shape-africas-data-privacy-laws&#x2F;a-72567105&quot;&gt;lose the right to determine how your data is used&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;10&quot;&gt;&lt;ins&gt;&lt;em&gt;The others are moving&lt;&#x2F;em&gt;:&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;publiccode.eu&#x2F;en&#x2F;&quot;&gt;Public money, public code&lt;&#x2F;a&gt; an initiative advocating that software developed with public funds should be made freely available under a free and open-source license.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;code.gouv.fr&#x2F;fr&#x2F;&quot;&gt;Pôle open source et communs numériques&lt;&#x2F;a&gt;, Initiative to support government administrations in using free and open source software, assist their efforts to publish and share source code, and create connections with the open source ecosystem.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.documentfoundation.org&#x2F;blog&#x2F;2024&#x2F;04&#x2F;04&#x2F;german-state-moving-30000-pcs-to-libreoffice&#x2F;&quot;&gt;The German federal state&lt;&#x2F;a&gt; has decided to move from Microsoft Windows and Microsoft Office to Linux and LibreOffice (and other free and open source software) on the 30,000 PCs used in the local government.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;eu-os.eu&#x2F;&quot;&gt;EU OS&lt;&#x2F;a&gt;, a proof-of-concept for an Operating System for a typical organization inside the European Union public sector.&lt;&#x2F;p&gt;
&lt;p&gt;To move away from dependence on US software solutions and acquire genuine digital sovereignty, the &lt;a href=&quot;https:&#x2F;&#x2F;www.lyon.fr&#x2F;actualite&#x2F;action-municipale&#x2F;la-ville-de-lyon-renforce-sa-souverainete-numerique&quot;&gt;City of Lyon&lt;&#x2F;a&gt; has embarked on a major transformation of its digital tools.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;At this point, I don&#x27;t even know what else should I say to convince you...&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.zdnet.com&#x2F;article&#x2F;why-denmark-is-dumping-microsoft-office-and-windows-for-libreoffice-and-linux&#x2F;&quot;&gt;Denmark&lt;&#x2F;a&gt; is transitioning away from Microsoft products in a key ministry due to a strategy focused on digital sovereignty and reducing reliance on foreign, particularly US-based, tech giants. This involves replacing Windows and Office 365 with open-source alternatives like Linux and LibreOffice.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;economictimes.indiatimes.com&#x2F;news&#x2F;international&#x2F;us&#x2F;after-danish-cities-germanys-schleswig-holstein-state-government-to-ban-microsoft-programs-at-work&#x2F;articleshow&#x2F;121833653.cms&quot;&gt;Schleswig-Holstein state&lt;&#x2F;a&gt; government is shifting completely to free and open source software, aiming to achieve what officials call &quot;digital sovereignty&quot; and to reduce reliance on U.S.-based tech giants [...] This isn’t just about software. It&#x27;s about control over sensitive data.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;11&quot;&gt;&lt;ins&gt;&lt;em&gt;You&#x27;re already consuming:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;If you&#x27;ve ever used &lt;a href=&quot;https:&#x2F;&#x2F;opensource.google&#x2F;&quot;&gt;Google&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;opensource.fb.com&#x2F;&quot;&gt;Facebook&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;whatsapp&quot;&gt;WhatsApp&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;opensource.microsoft.com&#x2F;&quot;&gt;Microsoft&lt;&#x2F;a&gt; or watched a &lt;a href=&quot;https:&#x2F;&#x2F;netflix.github.io&#x2F;&quot;&gt;Netflix&lt;&#x2F;a&gt; movie today, you&#x27;ve been relying on free and open source software without even knowing it. These tech giants don&#x27;t reinvent the wheel, they build their services on top of thousands of open source projects. None of those things would exist without free and open source software.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;13&quot;&gt;Skepticism:&lt;&#x2F;h2&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 300px&quot; src=&quot;&#x2F;images&#x2F;skeptic.jpg&quot; alt=&quot;skeptical&quot; title=&quot;If free software is so great, why do I get the feeling that no one uses it?&quot;&#x2F;&gt;
&lt;p&gt;Technological proficiency is important, but &lt;strong&gt;correctly managing the cultural&lt;&#x2F;strong&gt; shift required to embrace free and open source software is also very important. There are a number of &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=5GXGdavLu6Y&quot;&gt;complex reasons&lt;&#x2F;a&gt; why mass adoption of free and open software has not yet taken place in Africa.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cultural-resistance-and-habits&quot;&gt;&lt;ins&gt;&lt;em&gt;Cultural resistance and habits:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Users are used to the interfaces and workflows of proprietary software. Change naturally generates resistance, especially when the benefits are not immediately perceptible to the end-user.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;institutional-inertia&quot;&gt;&lt;ins&gt;&lt;em&gt;Institutional inertia:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Public and private organizations are often prisoners of their past technological choices. Migrating complex systems requires massive investment in training, data migration and process adaptation. This &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;shorts&#x2F;7RXK-nR83f4&quot;&gt;vendor lock-in&lt;&#x2F;a&gt; is particularly strong in public administration.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;perception-of-complexity-and-support&quot;&gt;&lt;ins&gt;&lt;em&gt;Perception of complexity and support:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;In my humble opinion, this perception no longer corresponds to current reality. Yet, many still consider free and open source software to be more technical and less user-friendly.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lobbying-and-political-influence&quot;&gt;&lt;ins&gt;&lt;em&gt;Lobbying and political influence:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Large technology companies exert considerable &lt;a href=&quot;https:&#x2F;&#x2F;corporateeurope.org&#x2F;en&#x2F;2023&#x2F;09&#x2F;lobbying-power-amazon-google-and-co-continues-grow&quot;&gt;influence&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;www.lbc.co.uk&#x2F;world-news&#x2F;british-icc-chief-prosecutor-lost-email-bank-accounts-frozen-trump-sanctions&#x2F;&quot;&gt;pressure&lt;&#x2F;a&gt; on political decisions and public procurement, hindering the adoption of alternative solutions.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;economic-reasons&quot;&gt;&lt;ins&gt;&lt;em&gt;Economic reasons:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Business models built around proprietary software generate huge revenues. Companies like Microsoft, Adobe or Oracle have built entire ecosystems that create mutual financial dependency. To change would represent considerable transition costs and a loss of revenue for many players.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;to-go-even-deeper-on-this-subject&quot;&gt;&lt;ins&gt;&lt;em&gt;To go even deeper on this subject:&lt;&#x2F;em&gt;&lt;&#x2F;ins&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Here is a really interesting &lt;a href=&quot;https:&#x2F;&#x2F;papers.ssrn.com&#x2F;sol3&#x2F;papers.cfm?abstract_id=3138085&quot;&gt;study&lt;&#x2F;a&gt;, intitled &lt;strong&gt;&lt;em&gt;Adoption Barriers of Open-Source Software: A Systematic Review&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; and led by &lt;a href=&quot;https:&#x2F;&#x2F;papers.ssrn.com&#x2F;sol3&#x2F;cf_dev&#x2F;AbsByAuth.cfm?per_id=2321721&quot;&gt;Dmitrij Petrov&lt;&#x2F;a&gt; &amp;amp; &lt;a href=&quot;https:&#x2F;&#x2F;papers.ssrn.com&#x2F;sol3&#x2F;cf_dev&#x2F;AbsByAuth.cfm?per_id=2544892&quot;&gt;Nikolaus Obwegeser&lt;&#x2F;a&gt;. A study that tried to find all the significant barriers that hinder the wider adoption of Free and Open source software. Have been found 19 high-level factors that challenge or inhibit the adoption of FLOSS in various contexts. Long story short....&lt;&#x2F;p&gt;
&lt;br&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 900px&quot; src=&quot;&#x2F;images&#x2F;adoption_barriers_of_foss.png&quot; alt=&quot;&quot; title=&quot;Barriers of FOSS&quot;&#x2F;&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h2 id=&quot;14&quot;&gt;How to contribute:&lt;&#x2F;h2&gt;
&lt;p&gt;There are so many &lt;a href=&quot;https:&#x2F;&#x2F;contribute.cncf.io&#x2F;contributors&#x2F;getting-started&#x2F;&quot;&gt;ways&lt;&#x2F;a&gt; to &lt;a href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;get-started&#x2F;exploring-projects-on-github&#x2F;finding-ways-to-contribute-to-open-source-on-github&quot;&gt;contribute&lt;&#x2F;a&gt; to free and open source software. There are so many &lt;a href=&quot;https:&#x2F;&#x2F;www.freecodecamp.org&#x2F;news&#x2F;how-to-contribute-to-open-source-projects-beginners-guide&#x2F;#:~:text=Adding%20a%20description%20to%20a,the%20project%27s%20work%20folder%20correctly.&quot;&gt;articles&lt;&#x2F;a&gt;, so many &lt;a href=&quot;https:&#x2F;&#x2F;opensource.guide&#x2F;how-to-contribute&#x2F;&quot;&gt;guides&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;dev.to&#x2F;opensauced&#x2F;how-i-got-hired-contributing-to-open-source-projects-546i&quot;&gt;tutorials&lt;&#x2F;a&gt;. The choice is &lt;a href=&quot;https:&#x2F;&#x2F;www.digitalocean.com&#x2F;resources&#x2F;articles&#x2F;how-to-contribute-to-open-source&quot;&gt;yours&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If you really want me to answer the question, this is more or less how it should be done (on top of my head).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;0-contribution-types&quot;&gt;0. Contribution types:&lt;&#x2F;h4&gt;
&lt;p&gt;There are several ways you can contribute to free and open source projects.&lt;&#x2F;p&gt;
&lt;p&gt;Bug fixes involve addressing opened issues, improving error handling, and resolving technical problems that users have encountered. Feature contributions include adding new functionality, enhancing user experience and interface design, and optimizing performance to make applications run more efficiently.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;diataxis.fr&#x2F;&quot;&gt;Documentation&lt;&#x2F;a&gt; improvements focus on enhancing readability, adding helpful examples and tutorials, providing translations for broader accessibility, and fixing typos or grammatical errors.&lt;&#x2F;p&gt;
&lt;p&gt;The last contribution type I would like to talk about is funding. Funding through &lt;a href=&quot;https:&#x2F;&#x2F;my.fsf.org&#x2F;join&quot;&gt;donating&lt;&#x2F;a&gt; or direct &lt;a href=&quot;https:&#x2F;&#x2F;palletsprojects.com&#x2F;donate&quot;&gt;sponsoring&lt;&#x2F;a&gt; can provide crucial financial support to help free and open source projects continue their development.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;1-tips&quot;&gt;1. Tips:&lt;&#x2F;h4&gt;
&lt;p&gt;Before diving into contributions, it&#x27;s essential to read the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;django&#x2F;django&#x2F;blob&#x2F;main&#x2F;CONTRIBUTING.rst&quot;&gt;CONTRIBUTING.md&lt;&#x2F;a&gt; file or any other available documentation to understand the project&#x27;s specific guidelines and processes.&lt;&#x2F;p&gt;
&lt;p&gt;Starting small with simple fixes like correcting typos or &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;numpy&#x2F;numpy&#x2F;issues&#x2F;29258&quot;&gt;improving documentation&lt;&#x2F;a&gt; can be incredibly valuable and help you get familiar with the contribution workflow.&lt;&#x2F;p&gt;
&lt;p&gt;Remember to be patient during the review process, as &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;django&#x2F;django&#x2F;pull&#x2F;19565&quot;&gt;reviews&lt;&#x2F;a&gt; are conducted by human beings who need time to thoroughly examine your work. Don&#x27;t hesitate to ask &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=5k0ndcJiECo&quot;&gt;questions&lt;&#x2F;a&gt; when you&#x27;re stuck, and feel free to ask even more &lt;a href=&quot;https:&#x2F;&#x2F;palletsprojects.com&#x2F;contributing&#x2F;questions&quot;&gt;questions&lt;&#x2F;a&gt; to clarify requirements or processes.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s also important to focus on making one logical change per Pull Request to keep your contributions clear and manageable for reviewers.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;2-discover-explore&quot;&gt;2. Discover &amp;amp; explore:&lt;&#x2F;h4&gt;
&lt;p&gt;Begin your open source journey by &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;firstcontributions&#x2F;first-contributions&quot;&gt;finding&lt;&#x2F;a&gt; a project that you &lt;strong&gt;actively use&lt;&#x2F;strong&gt; or &lt;strong&gt;genuinely care about&lt;&#x2F;strong&gt;, as this personal connection will help sustain your &lt;strong&gt;motivation&lt;&#x2F;strong&gt;. Take time to thoroughly read the project&#x27;s documentation and contributing guidelines to understand how the community operates and what standards they maintain. Browse through the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;numpy&#x2F;numpy&#x2F;issues&quot;&gt;project&#x27;s issues&lt;&#x2F;a&gt; section, paying special attention to those tagged with &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jazzband&#x2F;django-silk&#x2F;issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22&quot;&gt;&quot;good first issue&quot;&lt;&#x2F;a&gt; or &quot;beginner&quot; labels, as these are specifically designed to help newcomers get started with meaningful contributions.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;3-setup-your-environment&quot;&gt;3. Setup your environment:&lt;&#x2F;h4&gt;
&lt;p&gt;Getting started with development requires setting up your workspace properly. First, &lt;a href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;pull-requests&#x2F;collaborating-with-pull-requests&#x2F;working-with-forks&#x2F;fork-a-repo&quot;&gt;fork&lt;&#x2F;a&gt; the repository to create your own copy of the project. Next, &lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-clone&quot;&gt;clone&lt;&#x2F;a&gt; this forked repository to your local machine where you can make changes and test your work.&lt;&#x2F;p&gt;
&lt;p&gt;Take time to set up the development environment according to the project&#x27;s instructions, which may involve &lt;a href=&quot;#&quot;&gt;installing&lt;&#x2F;a&gt; specific dependencies or configuring tools. Run any available &lt;a href=&quot;#&quot;&gt;unit tests&lt;&#x2F;a&gt; to ensure everything is working correctly in your setup, as this confirms your environment is properly configured. Finally, &lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-switch&quot;&gt;create a new branch&lt;&#x2F;a&gt; for your work to keep your changes organized and separate from the main codebase.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;4-make-your-contribution&quot;&gt;4. Make your contribution:&lt;&#x2F;h4&gt;
&lt;p&gt;When working on your contribution, it&#x27;s crucial to follow the project&#x27;s established &lt;a href=&quot;https:&#x2F;&#x2F;peps.python.org&#x2F;pep-0008&#x2F;&quot;&gt;coding style and conventions&lt;&#x2F;a&gt; to maintain consistency across the codebase. Focus on writing your code, fixing bugs, or adding features while keeping the project&#x27;s standards and best practices in mind. Remember to update &lt;a href=&quot;#&quot;&gt;documentation&lt;&#x2F;a&gt; whenever your changes affect how users or developers interact with the project. Additionally, add or update &lt;a href=&quot;#&quot;&gt;tests&lt;&#x2F;a&gt; to cover your changes, ensuring that new functionality works as expected and that bug fixes prevent regression.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;5-test-prepare&quot;&gt;5. Test &amp;amp; prepare&lt;&#x2F;h4&gt;
&lt;p&gt;Before submitting your work, thoroughly &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;django&#x2F;django&#x2F;tree&#x2F;main&#x2F;tests&quot;&gt;test&lt;&#x2F;a&gt; your changes by running tests locally to catch any issues early in the process. Carefully review your changes to ensure they meet the project&#x27;s quality standards and actually solve the intended problem.&lt;&#x2F;p&gt;
&lt;p&gt;Write clear, &lt;a href=&quot;https:&#x2F;&#x2F;www.conventionalcommits.org&#x2F;en&#x2F;v1.0.0&#x2F;&quot;&gt;descriptive commit messages&lt;&#x2F;a&gt; that explain what your changes do and why they were necessary, as this helps maintainers understand your contribution. Double-check your work against the &lt;a href=&quot;https:&#x2F;&#x2F;docs.djangoproject.com&#x2F;en&#x2F;dev&#x2F;internals&#x2F;contributing&#x2F;&quot;&gt;contributing guide&lt;&#x2F;a&gt; to make sure you&#x27;ve followed all the project&#x27;s requirements and conventions.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;6-submit-your-work&quot;&gt;6. Submit your work&lt;&#x2F;h4&gt;
&lt;p&gt;Once your contribution is ready, &lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-push&quot;&gt;push&lt;&#x2F;a&gt; your branch to your forked repository to make it available for review. Create a &lt;a href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;pull-requests&#x2F;collaborating-with-pull-requests&#x2F;proposing-changes-to-your-work-with-pull-requests&#x2F;about-pull-requests&quot;&gt;Pull Request&lt;&#x2F;a&gt; from your branch to the original project&#x27;s main branch, providing a clear pathway for your changes to be reviewed and potentially merged.&lt;&#x2F;p&gt;
&lt;p&gt;Fill out the PR template with detailed information about what your changes do, why they&#x27;re needed, and how they&#x27;ve been tested. If your contribution addresses specific issues, link those related issues in your PR description to provide context and help maintainers track the resolution of reported problems.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;7-collaborate-refine&quot;&gt;7. Collaborate &amp;amp; refine&lt;&#x2F;h4&gt;
&lt;p&gt;After submitting your Pull Request, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;healthsites&#x2F;healthsites&#x2F;pulls?q=+is%3Apr+author%3Alemeteore+&quot;&gt;actively engage with the review process&lt;&#x2F;a&gt; by responding promptly and thoughtfully to code review feedback from maintainers and other contributors. Make any requested changes to address concerns or suggestions, treating each piece of feedback as an opportunity to improve your contribution and learn from experienced developers.&lt;&#x2F;p&gt;
&lt;p&gt;Throughout this process, engage in discussions &lt;strong&gt;respectfully and professionally&lt;&#x2F;strong&gt;, remembering that constructive feedback is meant to help improve the project rather than criticize your work personally. Pay attention to any failing CI checks and address them promptly, as these automated tests help ensure your changes don&#x27;t break existing functionality.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;8-merge-celebrate&quot;&gt;8. Merge &amp;amp; celebrate:&lt;&#x2F;h4&gt;
&lt;p&gt;Your contribution gets merged into the main project, congratulations 🎉. This marks a significant achievement in your open source journey. You&#x27;re now officially a project contributor, joining a community of developers who have helped shape and improve the software. Most importantly, your code now helps users worldwide, potentially solving problems, adding useful features, or improving the experience for countless people who rely on the project.&lt;&#x2F;p&gt;
&lt;p&gt;Here is an &lt;a href=&quot;https:&#x2F;&#x2F;www.cncf.io&#x2F;blog&#x2F;2023&#x2F;04&#x2F;03&#x2F;outlining-the-structure-of-your-open-source-software-project&#x2F;&quot;&gt;article&lt;&#x2F;a&gt; discussing, among other things, the tasks that are needed to be taken care of for different sizes of the open source project. We see that the bigger the project, the more ways there are to contribute.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;15&quot;&gt;Success stories:&lt;&#x2F;h2&gt;
&lt;p&gt;After &lt;a href=&quot;https:&#x2F;&#x2F;x.com&#x2F;fossfa&quot;&gt;searching&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;www.crunchbase.com&#x2F;organization&#x2F;fossfa&quot;&gt;very&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;FOSSFA&quot;&gt;extensively&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;www.instagram.com&#x2F;fossfa&#x2F;&quot;&gt;everywhere&lt;&#x2F;a&gt; on the internet, I found no &lt;strong&gt;current&lt;&#x2F;strong&gt; organizations in Africa, that even remotely resembles the Free Software Foundation.&lt;&#x2F;p&gt;
&lt;p&gt;If you find interesting (and recent) informations about free and open source software initiaves&#x2F;organizations in Africa, if you are in one way or another, linked to an active Linux User Group in Africa, please, if you know any African initiative&#x2F;organization that promotes free and open source software in Africa, please let me know. I&#x27;ll be glad to update the article.&lt;&#x2F;p&gt;
&lt;br&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 500px&quot; src=&quot;&#x2F;images&#x2F;open-source-contributions.jpg&quot; alt=&quot;&quot; title=&quot;Hopefully, you won&#x27;t leave! Because we need your help!&quot;&#x2F;&gt;
&lt;h2 id=&quot;16&quot;&gt;More on the topic:&lt;&#x2F;h2&gt;
&lt;p&gt;We could easily spend days on this topic! Since we only have two hours, here are some excellent resources to continue your journey into this fascinating subject.&lt;&#x2F;p&gt;
&lt;p&gt;In french:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Ef8jkpJEDVc&quot;&gt;La liberté du logiciel expliquée en moins de 3 min!&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Xazuo7Rva2Y&quot;&gt;Se lancer dans l&#x27;open source à 100% (et en vivre !)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=JWJmFTcH1Bw&quot;&gt;Le logiciel libre comme levier de souveraineté&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=YQTEq9BRefo&quot;&gt;Open Source: Comprendre, Contribuer&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=y4AjuV0O3wo&quot;&gt;Comment devenir un contributeur Open Source ?&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=8U80yLOZLp4&quot;&gt;Open source &amp;amp; logiciel libre&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In english:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=PVD1LNDxOnc&quot;&gt;Open Source explained&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;opensource.guide&#x2F;how-to-contribute&#x2F;&quot;&gt;How to contribute to Open Source&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.digitalocean.com&#x2F;resources&#x2F;articles&#x2F;how-to-contribute-to-open-source&quot;&gt;How to contribute to Open Source, a step by step guide&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;philosophy&#x2F;open-source-misses-the-point.en.html&quot;&gt;Why Open Source misses the point of Free Software&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;lwn.net&#x2F;Articles&#x2F;1013776&#x2F;&quot;&gt;Lessons from open source in the Mexican government&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Let&#x27;s be optimistic:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;livingopensource.org&#x2F;the-rise-of-open-source-software-in-africa-current-trends-and-futureprospects&#x2F;&quot;&gt;The rise of Open Source software in Africa: current trends and future prospects&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.africantechroundup.com&#x2F;open-source-proprietary-software-african-tech-round-up&#x2F;&quot;&gt;Open Source vs proprietary software: what is best for Africa?&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.ictworks.org&#x2F;digital-colonialism-african-software-development&#x2F;&quot;&gt;How to break digital colonialism in African software development&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.universityworldnews.com&#x2F;post.php?story=20241203094802197&quot;&gt;Ten university teams worked on open-source operating system&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;By the way...:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The Free Software Foundation (FSF) &lt;a href=&quot;https:&#x2F;&#x2F;www.fsf.org&#x2F;fsf40&quot;&gt;turns forty&lt;&#x2F;a&gt; this year&lt;&#x2F;li&gt;
&lt;li&gt;PyCon Africa and PyConZA are &lt;a href=&quot;https:&#x2F;&#x2F;za.pycon.org&#x2F;&quot;&gt;joining forces!&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;2025.djangocon.africa&#x2F;&quot;&gt;DjangoCon Africa&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Co-locating &lt;a href=&quot;https:&#x2F;&#x2F;discourse.ubuntu.com&#x2F;t&#x2F;ubucon-africa-djangocon-africa-2025&#x2F;59940&quot;&gt;the 1st UbuCon Africa with the passionate Django community!&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;oshwa.org&#x2F;about&#x2F;&quot;&gt;The Open Source Hardware Association&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Framework &lt;a href=&quot;https:&#x2F;&#x2F;frame.work&#x2F;about&quot;&gt;electronics are open to repair and upgrade&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In the next few weeks, I will publish findings regarding the &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;ssssss&#x2F;&quot;&gt;Syndromic Surveillance System&lt;&#x2F;a&gt; I&#x27;m currently working on. Expect a detailed writeup showing exactly how free and open source software is driving a positive change to the West Africa&#x27;s public health infrastructure. Stay tuned...&lt;&#x2F;p&gt;
&lt;br&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 200px&quot; src=&quot;&#x2F;images&#x2F;stay_tuned.gif&quot; alt=&quot;&quot; title=&quot;stay tuned&quot;&#x2F;&gt;
&lt;p&gt;Thanks for sharing!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>C Pointers</title>
        <published>2024-06-18T00:00:00+00:00</published>
        <updated>2024-06-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/ptrs/"/>
        <id>https://nskm.xyz/posts/ptrs/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/ptrs/">&lt;p&gt;In my &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;&quot;&gt;last&lt;&#x2F;a&gt; post, I&#x27;ve written about lots of things but not about C pointers. I thought the topic deserves a post in itself because it&#x27;s one of the most important features of the C language.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s start with some &lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=24ntpKNiUMs&quot;&gt;music&lt;&#x2F;a&gt; please.&lt;&#x2F;p&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 550px&quot; src=&quot;&#x2F;assets&#x2F;pointers.png&quot; alt=&quot;C Pointers&quot; title=&quot;C Pointers&quot;&#x2F;&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h2 id=&quot;toc&quot;&gt;ToC&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;ptrs&#x2F;#i&quot;&gt;Introduction&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;ptrs&#x2F;#d&quot;&gt;Declaration &amp;amp; initialization&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;ptrs&#x2F;#o&quot;&gt;Operators&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;ptrs&#x2F;#u&quot;&gt;Use cases&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;ptrs&#x2F;#a&quot;&gt;Arrays &amp;amp; strings manipulation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;ptrs&#x2F;#p&quot;&gt;Pass by reference&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;ptrs&#x2F;#m&quot;&gt;Memory allocation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;ptrs&#x2F;#s&quot;&gt;Data structure implementation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;ptrs&#x2F;#f&quot;&gt;Functions pointers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;ptrs&#x2F;#h&quot;&gt;Hardware interface&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;ptrs&#x2F;#g&quot;&gt;Going further&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;i&quot;&gt;Introduction:&lt;&#x2F;h2&gt;
&lt;p&gt;A pointer is a variable that contains the memory address of another variable. A pointer allows
us to &lt;em&gt;indirectly&lt;&#x2F;em&gt; access and manipulate the value of the variable that is pointed to. Like other variables, C pointers have a type.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img
    style=&quot;display: block; margin: 0 auto; width: 600px&quot;
    src=&quot;&#x2F;assets&#x2F;pointers_repr.png&quot;
    alt=&quot;Pointers&quot;
    title=&quot;Pointers&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
  &lt;center&gt;
    &lt;a href=&quot;https:&#x2F;&#x2F;codeforwin.org&quot;&gt;Source&lt;&#x2F;a&gt;
  &lt;&#x2F;center&gt;
&lt;h2 id=&quot;d&quot;&gt;Declaration and initialization:&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main () {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; foo = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;42&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; bar = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;83&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int *&lt;&#x2F;span&gt;&lt;span&gt;ptr = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;foo;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; Pointer variable, type int, receives the address of foo variable*
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int **&lt;&#x2F;span&gt;&lt;span&gt;ptrptr = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;ptr; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; pointer to a pointer
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Value of foo: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, foo);
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Value of ptr is: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%p&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;, and ptr is pointing to: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void *&lt;&#x2F;span&gt;&lt;span&gt;)ptr, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;ptr);
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Value of ptrptr is: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%p&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt; &amp;amp; ptrptr is pointing to: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%p&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void *&lt;&#x2F;span&gt;&lt;span&gt;)ptrptr, (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void *&lt;&#x2F;span&gt;&lt;span&gt;)ptr);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;ptr = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;12&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Value of foo after modification via ptr: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, foo);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span&gt;ptrptr = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Value of foo after modification via ptr to ptr: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, foo);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  ptr = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;bar;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Value of ptr is now: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%p&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;, and ptr is now pointing to: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void *&lt;&#x2F;span&gt;&lt;span&gt;)ptr, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;ptr);
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Value of ptrptr, still: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%p&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt; &amp;amp; ptrptr is now pointing to: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%p&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void *&lt;&#x2F;span&gt;&lt;span&gt;)ptrptr, (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void *&lt;&#x2F;span&gt;&lt;span&gt;)ptr);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  exit(EXIT_SUCCESS);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And the output of the previous program is:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;Value of foo: 42
&lt;&#x2F;span&gt;&lt;span&gt;Value of ptr is: 0x7ffc6155fd60, and ptr is pointing to: 42
&lt;&#x2F;span&gt;&lt;span&gt;Value of ptrptr is: 0x7ffc6155fd68 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;ptrptr is pointing to: 0x7ffc6155fd60
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Value of foo after modification via ptr: 12
&lt;&#x2F;span&gt;&lt;span&gt;Value of foo after modification via ptr to ptr: 13
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Value of ptr is now: 0x7ffc6155fd64, and ptr is now pointing to: 83
&lt;&#x2F;span&gt;&lt;span&gt;Value of ptrptr, still: 0x7ffc6155fd68 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;ptrptr is now pointing to: 0x7ffc6155fd64
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;o&quot;&gt;C pointer operators:&lt;&#x2F;h2&gt;
&lt;p&gt;C offers operators for pointer manipulation:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Address-of operator (&amp;amp;): to return the memory address of a variable&lt;&#x2F;li&gt;
&lt;li&gt;Dereference operator (*): to access the value stored at the memory address pointed to&lt;&#x2F;li&gt;
&lt;li&gt;Arithmetic operators: to perform arithmetic operations on C pointers, addition (+), subtraction (-), increment (++), and decrement (--)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;u&quot;&gt;Use cases for C pointers:&lt;&#x2F;h2&gt;
&lt;p&gt;All modern programming languages have pointers in some form or other. Pointers are used everywhere there is a program, even when we don&#x27;t see them. Let&#x27;s explore some of those use cases.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a&quot;&gt;Manipulating array and string elements:&lt;&#x2F;h3&gt;
&lt;p&gt;C Pointers can be used to access and manipulate elements in arrays and strings. C Pointers provide a way to efficiently iterate over arrays and perform operations on each item of the sequence.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; arr[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;] = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int *&lt;&#x2F;span&gt;&lt;span&gt;aptr = arr;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; print items of the sequence using array indices
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;; i++) {
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, arr[i]);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; print elements of the array using pointer
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;; i++) {
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;aptr);
&lt;&#x2F;span&gt;&lt;span&gt;  aptr++;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; print items of the sequence using pointer arithmetic
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; and the fact that arr is actually a pointer to the first item of the arr
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;; i++) {
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;arr+i);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; an array of characters
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char&lt;&#x2F;span&gt;&lt;span&gt; str[] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Hello world from West Africa&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;sptr = str; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; a pointer to the first element of the array
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;while&lt;&#x2F;span&gt;&lt;span&gt;(i &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;28&lt;&#x2F;span&gt;&lt;span&gt;){
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; while i is less than 28, print the character at i-th index 
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, str[i]);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; increment i to go to the next index
&lt;&#x2F;span&gt;&lt;span&gt;  i++;
&lt;&#x2F;span&gt;&lt;span&gt; }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; while the value that is pointed to is different from the &amp;quot;\0&amp;quot; character
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;while &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;sptr != &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; print the char
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;sptr);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; increment pointer (to go to the next character)
&lt;&#x2F;span&gt;&lt;span&gt;  sptr = sptr + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; m = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;while&lt;&#x2F;span&gt;&lt;span&gt;(m &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;28&lt;&#x2F;span&gt;&lt;span&gt;){
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; str is actually a pointer to the first item of the object
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; so str+m is the address of the m-ieth item of the object
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;(str+m));
&lt;&#x2F;span&gt;&lt;span&gt;  m++;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; array of pointers to characters
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;names[] = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Alice&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Bob&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Charlie&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;David&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Emma&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; Pointer to the first element of the first element of the array of strings
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char **&lt;&#x2F;span&gt;&lt;span&gt;ptr_names = names; 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; j = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; j &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;; j++) {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; Print elements of the array of strings using indices
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, names[j]);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; x = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; x &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;; x++) {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; Print the element currently pointed to
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;ptr_names);
&lt;&#x2F;span&gt;&lt;span&gt;  ptr_names = ptr_names + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;p&quot;&gt;Passing arguments by reference:&lt;&#x2F;h3&gt;
&lt;p&gt;C Pointers can be used to pass arguments by reference to functions, allowing the function to modify the value of the original variable. This is particularly useful in the following situations:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;working with large data structures&lt;&#x2F;li&gt;
&lt;li&gt;you need to modify the value of a variable in a function&lt;&#x2F;li&gt;
&lt;li&gt;you need to optimize code by reducing the number of copies of data that need to be made&lt;&#x2F;li&gt;
&lt;li&gt;you need to return more than one value&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;string.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; let&amp;#39;s suppose this is a laaaaaarge struct
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;typedef struct &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; id;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char&lt;&#x2F;span&gt;&lt;span&gt; name[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;50&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;float&lt;&#x2F;span&gt;&lt;span&gt; salary;
&lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;Employee&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;update_employee(Employee&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span&gt;emp) {
&lt;&#x2F;span&gt;&lt;span&gt;  emp-&amp;gt;salary *= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1.1&lt;&#x2F;span&gt;&lt;span&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; 10% raise
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main() {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; We create the large structure once
&lt;&#x2F;span&gt;&lt;span&gt;  Employee e1 = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;John Doe&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5000&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Employee: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;, Salary: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, e1.name, e1.salary);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; We pass the large structure by reference
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; to avoid the overhead of copying the entire structure.
&lt;&#x2F;span&gt;&lt;span&gt;  update_employee(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;e1);
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Employee after update: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;, Salary: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, e1.name, e1.salary);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  exit(EXIT_SUCCESS);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;m&quot;&gt;Allocating memory:&lt;&#x2F;h3&gt;
&lt;p&gt;C Pointers are also used to allocate memory dynamically at run-time using functions like &lt;a href=&quot;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man3&#x2F;malloc.3.html&quot;&gt;malloc()&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man3&#x2F;calloc.3p.html&quot;&gt;calloc()&lt;&#x2F;a&gt;, and &lt;a href=&quot;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man3&#x2F;realloc.3p.html&quot;&gt;realloc()&lt;&#x2F;a&gt;. Examples:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;string.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; a huuuuuuuge structure
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;typedef struct &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; id;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char&lt;&#x2F;span&gt;&lt;span&gt; name[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;50&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;float&lt;&#x2F;span&gt;&lt;span&gt; salary;
&lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;Employee&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; thanks to pointer &amp;amp; to malloc,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; we can create the structure inside the create_employee function
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; and use the structure even after the function goes out of scope
&lt;&#x2F;span&gt;&lt;span&gt;Employee&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span&gt;create_employee(){
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; Allocate memory space on heap, size should be the same as width of Employee struct
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; Allocate a pointer on stack,
&lt;&#x2F;span&gt;&lt;span&gt;  Employee&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; e2 = malloc(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;sizeof&lt;&#x2F;span&gt;&lt;span&gt;(Employee));
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; always verify the allocation worked fine
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(e2 == nullptr) {
&lt;&#x2F;span&gt;&lt;span&gt;    printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Memory allocation failed!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    exit(EXIT_FAILURE);
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; the ptr e2 contains the value of the memory address of the struct that is on the heap  
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; e2;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;init_employee(Employee&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span&gt;emp, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;id, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;const char* &lt;&#x2F;span&gt;&lt;span&gt;name, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;float &lt;&#x2F;span&gt;&lt;span&gt;salary) {
&lt;&#x2F;span&gt;&lt;span&gt;  emp-&amp;gt;id = id;
&lt;&#x2F;span&gt;&lt;span&gt;  strcpy(emp-&amp;gt;name, name);
&lt;&#x2F;span&gt;&lt;span&gt;  emp-&amp;gt;salary = salary;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;update_employee(Employee&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span&gt;emp) {
&lt;&#x2F;span&gt;&lt;span&gt;  emp-&amp;gt;salary *= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1.1&lt;&#x2F;span&gt;&lt;span&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; 10% raise
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main() {
&lt;&#x2F;span&gt;&lt;span&gt;  Employee&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; e2 = create_employee();
&lt;&#x2F;span&gt;&lt;span&gt;  init_employee(e2, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Nsukami Patrick&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;6000&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Employee: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;, Salary: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, e2-&amp;gt;name, e2-&amp;gt;salary);
&lt;&#x2F;span&gt;&lt;span&gt;  update_employee(e2);
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Employee after update: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;, Salary: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, e2-&amp;gt;name, e2-&amp;gt;salary);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; never forget to free the allocated memory
&lt;&#x2F;span&gt;&lt;span&gt;  free(e2);
&lt;&#x2F;span&gt;&lt;span&gt;  exit(EXIT_SUCCESS);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;s&quot;&gt;Implementing data structures:&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;#&quot;&gt;Linked lists&lt;&#x2F;a&gt;, &lt;a href=&quot;#&quot;&gt;Stacks&lt;&#x2F;a&gt;, &lt;a href=&quot;#&quot;&gt;Queues&lt;&#x2F;a&gt;, &lt;a href=&quot;#&quot;&gt;Trees&lt;&#x2F;a&gt;, &lt;a href=&quot;#&quot;&gt;Graphs&lt;&#x2F;a&gt; and many other data structures are implemented using C Pointers. Example:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;f&quot;&gt;Calling functions:&lt;&#x2F;h3&gt;
&lt;p&gt;A function pointer, is a pointer which point to the memory address of a function instead of pointing to the address of a data object. They are used to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;store functions in data structures&lt;&#x2F;li&gt;
&lt;li&gt;pass functions as arguments to other functions&lt;&#x2F;li&gt;
&lt;li&gt;call functions dynamically at runtime&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Here are some &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;fp&#x2F;&quot;&gt;examples&lt;&#x2F;a&gt; on how to use function pointers in C.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;h&quot;&gt;Interfacing with hardware:&lt;&#x2F;h3&gt;
&lt;p&gt;C Pointers are often used in low-level programming to interact with hardware devices and memory-mapped registers. They provide a way to access specific memory addresses and manipulate hardware directly. This part goes way beyond what my brain is able to understand. Hopefully, I&#x27;ll be able to show you an example in another article.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;g&quot;&gt;Going further:&lt;&#x2F;h2&gt;
&lt;p&gt;To learn more about C pointers, we recommend the following &lt;strong&gt;pointers&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;SIN2jJm.png&quot;&gt;0x7ffc6155fd68&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Pointer_(dog_breed)&quot;&gt;0x7ffc6155fd69&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Pointer_(computer_programming)&quot;&gt;0x7ffc6155fd70&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;playlist?list=PLdo5W4Nhv31a8UcMN9-35ghv8qyFWD9_S&quot;&gt;0x7ffc6155fd71&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man1&#x2F;setleds.1.html&quot;&gt;0x7ffc6155fd72&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.adafruit.com&#x2F;product&#x2F;2264&quot;&gt;0x7ffc6155fd73&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 550px&quot; src=&quot;&#x2F;assets&#x2F;ptrs.jpg&quot; alt=&quot;Pointers&quot; title=&quot;Pointers&quot;&#x2F;&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>C</title>
        <published>2023-09-25T00:00:00+00:00</published>
        <updated>2023-09-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/cp/"/>
        <id>https://nskm.xyz/posts/cp/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/cp/">&lt;p&gt;I spent some time adding &lt;a href=&quot;https:&#x2F;&#x2F;www.logilab.fr&#x2F;blogentry&#x2F;13884378&quot;&gt;type annotations&lt;&#x2F;a&gt; to some Python code. Shoutout to all the people at &lt;a href=&quot;https:&#x2F;&#x2F;logilab.fr&quot;&gt;Logilab&lt;&#x2F;a&gt;, a really awesome team doing really awesome things. All those type annotations made me more and more interested in static typing... and in C programming.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Target audience&lt;&#x2F;strong&gt;&lt;&#x2F;em&gt;: people who already have an experience with programming. People who may have written some C programs in the past and who want to refresh their memory.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Context&lt;&#x2F;strong&gt;&lt;&#x2F;em&gt;: I&#x27;m working on:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;I&#x27;m working on &lt;code&gt;Linux 5.13.0-52-generic #59-Ubuntu SMP Wed Jun 15 20:17:13 UTC 2022 x86_64&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;And I&#x27;m using &lt;code&gt;GCC (Ubuntu 11.2.0-7ubuntu2) 11.2.0&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=6YSNKq-6SjM&quot;&gt;Music please&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 600px&quot; src=&quot;&#x2F;assets&#x2F;force.jpg&quot; alt=&quot;Force&quot; title=&quot;Force&quot;&#x2F;&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h2 id=&quot;toc&quot;&gt;ToC&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;#setup&quot;&gt;Setup&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;#primitive&quot;&gt;Primitive types&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;#integers&quot;&gt;integers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;#floats&quot;&gt;floats&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;#bool&quot;&gt;booleans&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;#void&quot;&gt;void&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;#composite&quot;&gt;Composite types&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;#structs&quot;&gt;structs&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;#enums&quot;&gt;enums&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;#unions&quot;&gt;unions&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;#arrays&quot;&gt;arrays&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;#strings&quot;&gt;strings&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;cp&#x2F;#constants&quot;&gt;Constants&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;setup&quot;&gt;The setup:&lt;&#x2F;h2&gt;
&lt;p&gt;To write C programs, we need:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;a href=&quot;#&quot;&gt;operating system&lt;&#x2F;a&gt; that respect your freedom and privacy.&lt;&#x2F;li&gt;
&lt;li&gt;A C compiler such as &lt;a href=&quot;https:&#x2F;&#x2F;gcc.gnu.org&#x2F;&quot;&gt;gcc&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;clang.llvm.org&#x2F;&quot;&gt;clang&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;emacs&#x2F;&quot;&gt;text editor&lt;&#x2F;a&gt; that &lt;a href=&quot;&#x2F;images&#x2F;trollface.jpg&#x2F;&quot;&gt;&lt;em&gt;respects&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; your freedom and privacy.&lt;&#x2F;li&gt;
&lt;li&gt;(Optional) a Bash script to generate the project &lt;a href=&quot;&#x2F;snips&#x2F;scfldc&#x2F;&quot;&gt;boilerplate&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;(Optional) a &lt;a href=&quot;&#x2F;snips&#x2F;scfldc&#x2F;&quot;&gt;Makefile&lt;&#x2F;a&gt; to format, build, install and run the program quickly.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;h2 id=&quot;types&quot;&gt;Types:&lt;&#x2F;h2&gt;
&lt;p&gt;Variable, a named location in the computer&#x27;s memory where data can be stored and accessed. Type, define the size, the format, the behavior, the operations that can be performed on the variable. Let&#x27;s talk about the common types in C programming.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;primitive&quot;&gt;Primitive types:&lt;&#x2F;h2&gt;
&lt;p&gt;Primitive data types, or &quot;basic data types&quot; or &quot;fundamental data types&quot; are the most basic data types that can be used for representing simple values such as numbers, characters, etc... The primitive data types are...&lt;&#x2F;p&gt;
&lt;h3 id=&quot;integers&quot;&gt;Integer types&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;char: represents a single character (usually 1 byte)&lt;&#x2F;li&gt;
&lt;li&gt;short: represents a small integer&lt;&#x2F;li&gt;
&lt;li&gt;int: represents an integer&lt;&#x2F;li&gt;
&lt;li&gt;long: represents a long integer&lt;&#x2F;li&gt;
&lt;li&gt;long long: represents a very long integer&lt;&#x2F;li&gt;
&lt;li&gt;unsigned short: represent a small positive integer&lt;&#x2F;li&gt;
&lt;li&gt;unsigned int: represents a positive integer&lt;&#x2F;li&gt;
&lt;li&gt;unsigned long: represents a long positive integer&lt;&#x2F;li&gt;
&lt;li&gt;unsigned long long: represents a very long positive integer&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This list is not exhaustive, there is also what we call &lt;strong&gt;fixed width integer types&lt;&#x2F;strong&gt; and what we call &lt;strong&gt;minimum width integer types&lt;&#x2F;strong&gt;. We won&#x27;t talk about them here, please browse this &lt;a href=&quot;https:&#x2F;&#x2F;pubs.opengroup.org&#x2F;onlinepubs&#x2F;9699919799&#x2F;basedefs&#x2F;stdint.h.html&quot;&gt;link&lt;&#x2F;a&gt; for reference.&lt;&#x2F;p&gt;
&lt;p&gt;To find the range of a particular type, we can look for the &lt;code&gt;limits.h&lt;&#x2F;code&gt; file  &lt;a href=&quot;https:&#x2F;&#x2F;pubs.opengroup.org&#x2F;onlinepubs&#x2F;9699919799&#x2F;basedefs&#x2F;limits.h.html&quot;&gt;online&lt;&#x2F;a&gt;. Or, we can also look for the same file inside our computer:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;lim  (trunk &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;%) &amp;gt;&amp;gt; find &#x2F;usr -type f -name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;limits.h&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;src&#x2F;linux-headers-5.13.0-51&#x2F;include&#x2F;linux&#x2F;limits.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;src&#x2F;linux-headers-5.13.0-51&#x2F;include&#x2F;uapi&#x2F;linux&#x2F;limits.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;src&#x2F;linux-headers-5.13.0-51&#x2F;include&#x2F;vdso&#x2F;limits.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;src&#x2F;linux-headers-5.13.0-52&#x2F;include&#x2F;linux&#x2F;limits.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;src&#x2F;linux-headers-5.13.0-52&#x2F;include&#x2F;uapi&#x2F;linux&#x2F;limits.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;src&#x2F;linux-headers-5.13.0-52&#x2F;include&#x2F;vdso&#x2F;limits.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;include&#x2F;linux&#x2F;limits.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;include&#x2F;c++&#x2F;11&#x2F;tr1&#x2F;limits.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;include&#x2F;limits.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;lib&#x2F;gcc&#x2F;x86_64-linux-gnu&#x2F;11&#x2F;include&#x2F;limits.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;perl5&#x2F;5.32&#x2F;Tk&#x2F;pTk&#x2F;compat&#x2F;limits.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;lib&#x2F;llvm-13&#x2F;lib&#x2F;clang&#x2F;13.0.0&#x2F;include&#x2F;limits.h
&lt;&#x2F;span&gt;&lt;span&gt;lim  (trunk &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;%) &amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we open, let&#x27;s say, the file &lt;code&gt;&#x2F;usr&#x2F;include&#x2F;limits.h&lt;&#x2F;code&gt;, we can see interesting informations like :&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#   define CHAR_MAX     UCHAR_MAX
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#  else
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#   define CHAR_MIN     SCHAR_MIN
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#   define CHAR_MAX     SCHAR_MAX
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#  endif
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;* Minimum and maximum values a `signed short int&amp;#39; can hold.  *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#  define SHRT_MIN      (&lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;32768&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#  define SHRT_MAX      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;32767
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;* Maximum value an `unsigned short int&amp;#39; can hold.  (Minimum is 0.)  *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#  define USHRT_MAX     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;65535
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;* Minimum and maximum values a `signed int&amp;#39; can hold.  *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#  define INT_MIN       (&lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;INT_MAX &lt;&#x2F;span&gt;&lt;span&gt;- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#  define INT_MAX       &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2147483647
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;* Maximum value an `unsigned int&amp;#39; can hold.  (Minimum is 0.)  *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#  define UINT_MAX      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;4294967295&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;U
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;* Minimum and maximum values a `signed long int&amp;#39; can hold.  *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#  if __WORDSIZE == 64
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#   define LONG_MAX     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;9223372036854775807&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;L
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#  else
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#   define LONG_MAX     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2147483647&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;L
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;floats&quot;&gt;Floating-point types:&lt;&#x2F;h3&gt;
&lt;p&gt;Used to represent real numbers with decimal points. More informations &lt;a href=&quot;https:&#x2F;&#x2F;pubs.opengroup.org&#x2F;onlinepubs&#x2F;9699919799&#x2F;basedefs&#x2F;float.h.html&quot;&gt;here&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;float: represents a single-precision floating-point number&lt;&#x2F;li&gt;
&lt;li&gt;double: represents a double-precision floating-point number&lt;&#x2F;li&gt;
&lt;li&gt;long double: represents an extended-precision floating-point number&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Here is an example showing how to use float values:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main() {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char&lt;&#x2F;span&gt;&lt;span&gt; input[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;float&lt;&#x2F;span&gt;&lt;span&gt; radius, area;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Enter the radius of the circle: &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;(fgets(input, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;sizeof&lt;&#x2F;span&gt;&lt;span&gt; input, stdin) != &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    radius = strtof(input, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    area = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3.14 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; radius &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; radius;
&lt;&#x2F;span&gt;&lt;span&gt;    printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Area of the circle: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, area);
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;  exit(EXIT_SUCCESS);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I have found the file containing all the constants definitions for float values, but I am not (yet) able to correctly understand what&#x27;s going on in this header file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;lim  (trunk &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;%) &amp;gt;&amp;gt; find &#x2F;usr -type f -name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;float.h&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;include&#x2F;tcl8.6&#x2F;tcl-private&#x2F;compat&#x2F;float.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;include&#x2F;c++&#x2F;11&#x2F;tr1&#x2F;float.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;lib&#x2F;gcc&#x2F;x86_64-linux-gnu&#x2F;11&#x2F;include&#x2F;float.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;lib&#x2F;llvm-13&#x2F;lib&#x2F;clang&#x2F;13.0.0&#x2F;include&#x2F;float.h
&lt;&#x2F;span&gt;&lt;span&gt;lim  (trunk &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;%) &amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here is a snippet of things that may be of interest for anyone looking for the ranges:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;defined&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt; __STDC_VERSION__ &amp;amp;&amp;amp; __STDC_VERSION__ &amp;gt; 201710L
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;* Maximum finite positive value with MANT_DIG digits in the
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;   significand taking their maximum value.  *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#undef FLT_NORM_MAX
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#undef DBL_NORM_MAX
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#undef LDBL_NORM_MAX
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#define FLT_NORM_MAX    __FLT_NORM_MAX__
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#define DBL_NORM_MAX    __DBL_NORM_MAX__
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#define LDBL_NORM_MAX   __LDBL_NORM_MAX__
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;* Whether each type matches an IEC 60559 format (1 for format, 2 for
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;   format and operations).  *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#undef FLT_IS_IEC_60559
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#undef DBL_IS_IEC_60559
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#undef LDBL_IS_IEC_60559
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#define FLT_IS_IEC_60559        __FLT_IS_IEC_60559__
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#define DBL_IS_IEC_60559        __DBL_IS_IEC_60559__
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#define LDBL_IS_IEC_60559       __LDBL_IS_IEC_60559__
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;bool&quot;&gt;Boolean type:&lt;&#x2F;h3&gt;
&lt;p&gt;The data type that can have two possible values: true or false. Include the &lt;a href=&quot;https:&#x2F;&#x2F;pubs.opengroup.org&#x2F;onlinepubs&#x2F;9699919799&#x2F;basedefs&#x2F;stdbool.h.html&quot;&gt;&quot;stdbool.h&quot;&lt;&#x2F;a&gt; header file in your program to use this data type. Example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdbool.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;string.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;bool &lt;&#x2F;span&gt;&lt;span&gt;strtobool(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;const char* &lt;&#x2F;span&gt;&lt;span&gt;str) {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(strcmp(str, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;true&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span&gt;|| strcmp(str, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;else if &lt;&#x2F;span&gt;&lt;span&gt;(strcmp(str, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;false&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0 &lt;&#x2F;span&gt;&lt;span&gt;|| strcmp(str, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;0&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return false&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    fprintf(stderr, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Invalid input: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, str);
&lt;&#x2F;span&gt;&lt;span&gt;    exit(EXIT_FAILURE);
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main() {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char&lt;&#x2F;span&gt;&lt;span&gt; name[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char&lt;&#x2F;span&gt;&lt;span&gt; answer[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt; is_learning;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Enter your name: &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;(fgets(name, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;sizeof&lt;&#x2F;span&gt;&lt;span&gt; name, stdin) != &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Your name is &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, name);
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Are you learning C programming: &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;(fgets(answer, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;sizeof&lt;&#x2F;span&gt;&lt;span&gt; answer, stdin) != &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    is_learning = strtobool(answer);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(is_learning)
&lt;&#x2F;span&gt;&lt;span&gt;      printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Very good, keep learning.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;else
&lt;&#x2F;span&gt;&lt;span&gt;      printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;You should learn C programming.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;  exit(EXIT_SUCCESS);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;void&quot;&gt;Void type:&lt;&#x2F;h3&gt;
&lt;p&gt;Void is a keyword to use as a placeholder where you would put a data type, to represent &quot;no data&quot;. The void data type represents the absence of type. Void types are used in the following situations:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;to state that the specific type of the variable is not known &lt;em&gt;yet&lt;&#x2F;em&gt; (void pointers).&lt;&#x2F;li&gt;
&lt;li&gt;to state that the function returns no result (void functions).&lt;&#x2F;li&gt;
&lt;li&gt;to state that the function has no parameters.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT: We can&#x27;t directly dereference void pointers because the compiler doesn&#x27;t know the size or type of data being pointed to. We need to explicitly cast them to the correct type before dereferencing.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Here&#x27;s an example to illustrate the usage of void type:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; greet is a function that
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; returns no result
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; and takes an unkown&#x2F;undefined list of arguments
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;greet(){
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Hello world&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;main(){
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; notice how we can pass all the arguments we want
&lt;&#x2F;span&gt;&lt;span&gt;  greet(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3.14&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  exit(EXIT_SUCCESS);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A function declared with the void data type can&#x27;t return a value, we cannot use the return keyword inside a void function:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;cscripts  &amp;gt;&amp;gt; gcc main.c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;.&#x2F;a.out 
&lt;&#x2F;span&gt;&lt;span&gt;main.c: In function ‘greet’:
&lt;&#x2F;span&gt;&lt;span&gt;main.c:57:10: warning: ‘return’ with a value, in function returning void
&lt;&#x2F;span&gt;&lt;span&gt;   57 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|   return&lt;&#x2F;span&gt;&lt;span&gt; 5432&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|          &lt;&#x2F;span&gt;&lt;span&gt;^~~~
&lt;&#x2F;span&gt;&lt;span&gt;main.c:56:6: note: declared here
&lt;&#x2F;span&gt;&lt;span&gt;   56 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span&gt;void greet(void){
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|      &lt;&#x2F;span&gt;&lt;span&gt;^~~~~~
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Another example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; greet is a function that
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; returns an int
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; and takes no arguments
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;greet(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;){
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5432&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;main(){
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; Because greet returns a result, I can retrieve and print it
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Greet returned the value: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, greet());
&lt;&#x2F;span&gt;&lt;span&gt;  exit(EXIT_SUCCESS);
&lt;&#x2F;span&gt;&lt;span&gt;}                                                                                                            
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we try to pass an argument to the greet function, we will receive an error message:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;cscripts  &amp;gt;&amp;gt; gcc main.c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;.&#x2F;a.out 
&lt;&#x2F;span&gt;&lt;span&gt;main.c: In function ‘main’:
&lt;&#x2F;span&gt;&lt;span&gt;main.c:57:44: error: too many arguments to function ‘greet’
&lt;&#x2F;span&gt;&lt;span&gt;   57 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|   &lt;&#x2F;span&gt;&lt;span&gt;printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Greet returned the value: %d\n&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, greet(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|                                            &lt;&#x2F;span&gt;&lt;span&gt;^~~~~
&lt;&#x2F;span&gt;&lt;span&gt;main.c:52:5: note: declared here
&lt;&#x2F;span&gt;&lt;span&gt;   52 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span&gt;int greet(void){
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|     &lt;&#x2F;span&gt;&lt;span&gt;^~~~~
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Last example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;main(){
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; age = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5432&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char*&lt;&#x2F;span&gt;&lt;span&gt; name = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Nsukami_&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; foo is a pointer that point to a not yet knwon data type
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void*&lt;&#x2F;span&gt;&lt;span&gt; foo;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; let&amp;#39;s point to an integer
&lt;&#x2F;span&gt;&lt;span&gt;  foo = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;age;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; explicit cast to the correct type before dereferencing
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;age is &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;((&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int*&lt;&#x2F;span&gt;&lt;span&gt;)foo));
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; let&amp;#39;s point to something else, for ex, a string
&lt;&#x2F;span&gt;&lt;span&gt;  foo = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;name;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; explicit cast to the correct type before dereferencing
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Name is &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;((&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char**&lt;&#x2F;span&gt;&lt;span&gt;)foo));
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  exit(EXIT_SUCCESS);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;composite&quot;&gt;Composite types&lt;&#x2F;h2&gt;
&lt;p&gt;Any data type which can be constructed using the language&#x27;s primitive data types and other composite types.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;structs&quot;&gt;Structures:&lt;&#x2F;h3&gt;
&lt;p&gt;Structs (short for structure), a user-defined data type that allows us to group together related data items of different types. Those data items are known as members or fields.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; An address is something with 2 attributes
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; a city street AND an house number
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;typedef struct&lt;&#x2F;span&gt;&lt;span&gt; address {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char&lt;&#x2F;span&gt;&lt;span&gt; citystreet[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; housenumber;
&lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;Address&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;main() {
&lt;&#x2F;span&gt;&lt;span&gt;  Address my_address = {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Planet 42, Rue de la Liberté&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5432&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;I live in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;. My house number is: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%u&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, my_address.citystreet, my_address.housenumber);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; how to update one of the fields
&lt;&#x2F;span&gt;&lt;span&gt;  my_address.housenumber = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;443&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;I live in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;. My house number is now: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%u&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, my_address.citystreet, my_address.housenumber);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;enums&quot;&gt;Enum data type:&lt;&#x2F;h3&gt;
&lt;p&gt;An enumeration is a &lt;em&gt;special kind&lt;&#x2F;em&gt; of data type defined by the user. An enumeration consists of a set of constant &lt;em&gt;integers&lt;&#x2F;em&gt; that are named by the user.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;typedef enum&lt;&#x2F;span&gt;&lt;span&gt; Level {
&lt;&#x2F;span&gt;&lt;span&gt;  LOW = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  MEDIUM,
&lt;&#x2F;span&gt;&lt;span&gt;  HIGH
&lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;Level&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main() {
&lt;&#x2F;span&gt;&lt;span&gt;  Level level = MEDIUM;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;switch &lt;&#x2F;span&gt;&lt;span&gt;(level) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Low level&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;break&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Medium level&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;break&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;High level&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;break&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;default&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Unkown level value&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;  exit(EXIT_SUCCESS);
&lt;&#x2F;span&gt;&lt;span&gt;} 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We said earlier an enumeration is a &lt;em&gt;special kind&lt;&#x2F;em&gt; of data type because.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;unions&quot;&gt;Unions:&lt;&#x2F;h3&gt;
&lt;p&gt;An union is a user-defined data type that allows different data types to be stored in the same memory location. It enables us to create a variable that can hold different types of data, but only one type at a time.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; Struct that combines an enum and a union
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;typedef struct &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; The type of our object could be either INT, either FLOAT, either STRING
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;enum &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    INT,
&lt;&#x2F;span&gt;&lt;span&gt;    FLOAT,
&lt;&#x2F;span&gt;&lt;span&gt;    STRING
&lt;&#x2F;span&gt;&lt;span&gt;  } type;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; all 3 values share the same memory location, only one can be set
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; value can be a int OR a float OR a string
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;union &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; intValue;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;float&lt;&#x2F;span&gt;&lt;span&gt; floatValue;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char&lt;&#x2F;span&gt;&lt;span&gt; stringValue[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  } value;
&lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;Object&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; Function to print the object based on its type
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;print(Object o) {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; check the type of our object 
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;switch&lt;&#x2F;span&gt;&lt;span&gt;(o.type) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span&gt;INT:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; then access the correct value
&lt;&#x2F;span&gt;&lt;span&gt;      printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Integer: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, o.value.intValue);
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;break&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span&gt;FLOAT:
&lt;&#x2F;span&gt;&lt;span&gt;      printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Float: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, o.value.floatValue);
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;break&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;case&lt;&#x2F;span&gt;&lt;span&gt; STRING:
&lt;&#x2F;span&gt;&lt;span&gt;      printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;String: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, o.value.stringValue);
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;break&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main() {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; Creating objects of different types
&lt;&#x2F;span&gt;&lt;span&gt;  Object o1, o2, o3;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  o1.type = INT;
&lt;&#x2F;span&gt;&lt;span&gt;  o1.value.intValue = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  o2.type = FLOAT;
&lt;&#x2F;span&gt;&lt;span&gt;  o2.value.floatValue = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3.14&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  o3.type = STRING;
&lt;&#x2F;span&gt;&lt;span&gt;  strcpy(o3.value.stringValue, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Hello&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; Printing the data objects
&lt;&#x2F;span&gt;&lt;span&gt;  print(o1);
&lt;&#x2F;span&gt;&lt;span&gt;  print(o2);
&lt;&#x2F;span&gt;&lt;span&gt;  print(o3);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  exit(EXIT_SUCCESS);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;arrays&quot;&gt;Arrays:&lt;&#x2F;h3&gt;
&lt;p&gt;A type consisting of nonempty items of the same nature stored using contiguous memory location. The number of items (the size) never changes during the array lifetime. Example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;float&lt;&#x2F;span&gt;&lt;span&gt; numbers[] = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2.5&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3.8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;4.2&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1.9&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5.6&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; size = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;sizeof&lt;&#x2F;span&gt;&lt;span&gt;(numbers) &#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;sizeof&lt;&#x2F;span&gt;&lt;span&gt;(numbers[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;]);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;float&lt;&#x2F;span&gt;&lt;span&gt; sum = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;, average;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; size; i++) {
&lt;&#x2F;span&gt;&lt;span&gt;        sum += numbers[i];
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    average = sum &#x2F; size;
&lt;&#x2F;span&gt;&lt;span&gt;    printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Average: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, average);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    exit(EXIT_SUCCESS);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;strings&quot;&gt;Strings:&lt;&#x2F;h3&gt;
&lt;p&gt;A string is just a sequence of characters stored inside an array and ending with the null character: &#x27;\0&#x27;. We don&#x27;t have strings as we have them in Python programming.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main() {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char&lt;&#x2F;span&gt;&lt;span&gt; name[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Enter your name: &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;(fgets(name, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;sizeof&lt;&#x2F;span&gt;&lt;span&gt; name, stdin) != &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Your name is &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, name);
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;  exit(EXIT_SUCCESS);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To know what are the functions available for string manipulation, Python developers will type &lt;code&gt;help(str)&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;Help on &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;str &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;module builtins:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;str(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;object&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt; |  str(object=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; str
&lt;&#x2F;span&gt;&lt;span&gt; |  str(bytes_or_buffer[, encoding[, errors]]) -&amp;gt; str
&lt;&#x2F;span&gt;&lt;span&gt; |
&lt;&#x2F;span&gt;&lt;span&gt; |  Create a new string object &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;the given object. If encoding &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;or
&lt;&#x2F;span&gt;&lt;span&gt; |  errors &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;is &lt;&#x2F;span&gt;&lt;span&gt;specified, then the object must expose a data buffer
&lt;&#x2F;span&gt;&lt;span&gt; |  that will be decoded using the given encoding &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;and &lt;&#x2F;span&gt;&lt;span&gt;error handler.
&lt;&#x2F;span&gt;&lt;span&gt; |  Otherwise, returns the result of object.__str__() (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;defined)
&lt;&#x2F;span&gt;&lt;span&gt; |  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;or &lt;&#x2F;span&gt;&lt;span&gt;repr(object).
&lt;&#x2F;span&gt;&lt;span&gt; |  encoding defaults to sys.getdefaultencoding().
&lt;&#x2F;span&gt;&lt;span&gt; |  errors defaults to &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;strict&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;.
&lt;&#x2F;span&gt;&lt;span&gt; |
&lt;&#x2F;span&gt;&lt;span&gt; |  Methods defined here:
&lt;&#x2F;span&gt;&lt;span&gt; |
&lt;&#x2F;span&gt;&lt;span&gt; |  __add__(self, value, &#x2F;)
&lt;&#x2F;span&gt;&lt;span&gt; |      Return self+value.
&lt;&#x2F;span&gt;&lt;span&gt; |
&lt;&#x2F;span&gt;&lt;span&gt; |  __contains__(self, key, &#x2F;)
&lt;&#x2F;span&gt;&lt;span&gt; |      Return bool(key &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;self).
&lt;&#x2F;span&gt;&lt;span&gt; |
&lt;&#x2F;span&gt;&lt;span&gt; |  __eq__(self, value, &#x2F;)
&lt;&#x2F;span&gt;&lt;span&gt; |      Return self==value.
&lt;&#x2F;span&gt;&lt;span&gt; |
&lt;&#x2F;span&gt;&lt;span&gt; |  __format__(self, format_spec, &#x2F;)
&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;C developers will look inside the &lt;code&gt;&amp;lt;string.h&amp;gt;&lt;&#x2F;code&gt; header &lt;a href=&quot;https:&#x2F;&#x2F;pubs.opengroup.org&#x2F;onlinepubs&#x2F;009695399&#x2F;basedefs&#x2F;string.h.html&quot;&gt;file&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;nskm2  &amp;gt;&amp;gt; find &#x2F;usr&#x2F;include -type f -name &amp;quot;string.h&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;include&#x2F;linux&#x2F;string.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;include&#x2F;tcl8.6&#x2F;tcl-private&#x2F;compat&#x2F;string.h
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;include&#x2F;string.h
&lt;&#x2F;span&gt;&lt;span&gt;nskm2  &amp;gt;&amp;gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;They can also read the man pages, &lt;code&gt;man string&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;STRING(3)                                  Linux Programmer&amp;#39;s Manual                                 STRING(3)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;NAME
&lt;&#x2F;span&gt;&lt;span&gt;       stpcpy,  strcasecmp, strcat, strchr, strcmp, strcoll, strcpy, strcspn, strdup, strfry, strlen, strncat,
&lt;&#x2F;span&gt;&lt;span&gt;       strncmp, strncpy, strncasecmp, strpbrk, strrchr, strsep, strspn, strstr, strtok, strxfrm, index, rindex
&lt;&#x2F;span&gt;&lt;span&gt;       - string operations
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;SYNOPSIS
&lt;&#x2F;span&gt;&lt;span&gt;       #include &amp;lt;strings.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;       int strcasecmp(const char *s1, const char *s2);
&lt;&#x2F;span&gt;&lt;span&gt;              Compare the strings s1 and s2 ignoring case.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;       int strncasecmp(const char *s1, const char *s2, size_t n);
&lt;&#x2F;span&gt;&lt;span&gt;              Compare the first n bytes of the strings s1 and s2 ignoring case.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;       char *index(const char *s, int c);
&lt;&#x2F;span&gt;&lt;span&gt;              Return a pointer to the first occurrence of the character c in the string s.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;       char *rindex(const char *s, int c);
&lt;&#x2F;span&gt;&lt;span&gt;              Return a pointer to the last occurrence of the character c in the string s.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;       #include &amp;lt;string.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;       char *stpcpy(char *dest, const char *src);
&lt;&#x2F;span&gt;&lt;span&gt;              Copy a string from src to dest, returning a pointer to the end of the resulting string at dest.
&lt;&#x2F;span&gt;&lt;span&gt; Manual page string(3) line 1 (press h for help or q to quit)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;constants&quot;&gt;Constants:&lt;&#x2F;h2&gt;
&lt;p&gt;A fixed value that cannot be, &lt;em&gt;that should not&lt;&#x2F;em&gt; be changed during the execution of a program.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;If we have a fixed value that is used in calculations, we can define it as a constant to avoid hard-coding the value multiple times.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; let&amp;#39;s define PI as a constant
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;const int&lt;&#x2F;span&gt;&lt;span&gt; PI = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3.14159&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; radius = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; let&amp;#39;s reuse our constant
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; area = PI &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; radius &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; radius;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Trying to modify our constant will give us an error message:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;main.c: In function ‘main’:
&lt;&#x2F;span&gt;&lt;span&gt;main.c:129:6: error: assignment of read-only variable ‘PI’
&lt;&#x2F;span&gt;&lt;span&gt;  129 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|   &lt;&#x2F;span&gt;&lt;span&gt;PI = 4.5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|      &lt;&#x2F;span&gt;&lt;span&gt;^
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Another way to use constants is this one. Instead of using arbitrary numbers directly in your code, you can define them as constants with meaningful names to improve code readability and maintainability.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;const int&lt;&#x2F;span&gt;&lt;span&gt; LENGTH = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;const int&lt;&#x2F;span&gt;&lt;span&gt; MIN_AGE = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;const int&lt;&#x2F;span&gt;&lt;span&gt; MAX_AGE = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;50&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char&lt;&#x2F;span&gt;&lt;span&gt; input[LENGTH];
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; age;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Enter your age: &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;(fgets(input, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;sizeof&lt;&#x2F;span&gt;&lt;span&gt; input, stdin) != &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;  age = strtol(input, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(age &amp;lt; MIN_AGE || age &amp;gt; MAX_AGE) {
&lt;&#x2F;span&gt;&lt;span&gt;    printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt; is an invalid age! Please enter an age between &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt; and &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, age, MIN_AGE, MAX_AGE);
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;When declaring an array, we can use a constant to specify its size, making it easier to modify if needed.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; In this example, `ARRAY_SIZE` is declared as a constant to specify the size of an array. By using a
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; constant, you can easily change the size of the array by modifying the constant&amp;#39;s value in a single place.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;const int&lt;&#x2F;span&gt;&lt;span&gt; ARRAY_SIZE = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; arr[ARRAY_SIZE];
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;We can also declare function parameters as &lt;code&gt;const&lt;&#x2F;code&gt; to ensure that the function does not modify the parameter:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; This helps prevent accidental modifications and indicates that the function is read-only.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;print(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;const int &lt;&#x2F;span&gt;&lt;span&gt;arr[], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;size) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; i &amp;lt; size; i++) {
&lt;&#x2F;span&gt;&lt;span&gt;        printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, arr[i]);
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion:&lt;&#x2F;h2&gt;
&lt;p&gt;I really hope you&#x27;ve learned something. I did \o&#x2F; In the next episode, I will try to write about header files or pointers or something else depending on the current moon, the weather and the stars alignment. Also, thanks to &lt;a href=&quot;https:&#x2F;&#x2F;mastodon.social&#x2F;@orbifx&quot;&gt;Orbifx&lt;&#x2F;a&gt; for taking the time to answer all my questions.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;more-on-the-topic&quot;&gt;More on the topic:&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;hal.inria.fr&#x2F;hal-02383654&#x2F;file&#x2F;ModernC.pdf&quot;&gt;Modern C, Jens Gustedt&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;gnu-c-manual&#x2F;gnu-c-manual.pdf&quot;&gt;The GNU C Reference Manual&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;amjadmajid&#x2F;Makefile&quot;&gt;Explanation about how to write a Makefile&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.open-std.org&#x2F;jtc1&#x2F;sc22&#x2F;wg14&#x2F;www&#x2F;docs&#x2F;n2655.pdf&quot;&gt;Make false and true first-class language features v4
proposal for C23&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;on-a-completely-differnt-note&quot;&gt;On a completely differnt note:&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=snvzAfYOFks&quot;&gt;Des organismes aux algorithmes, l&#x27;odyssée computationnelle du vivant | Xavier Berthet | TEDxINPENSAT&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;2023.djangocon.africa&#x2F;&quot;&gt;The first DjangoCon Africa, in Zanzibar, Tanzania.&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Decorators</title>
        <published>2023-02-06T00:00:00+00:00</published>
        <updated>2023-02-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/decor/"/>
        <id>https://nskm.xyz/posts/decor/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/decor/">&lt;p&gt;I was watching a &lt;em&gt;really&lt;&#x2F;em&gt; interesting &lt;a href=&quot;https:&#x2F;&#x2F;y.com.sb&#x2F;watch?v=RL7BECNn-RI&quot;&gt;video&lt;&#x2F;a&gt; about buildings architecture in New York, when one of my &lt;a href=&quot;https:&#x2F;&#x2F;dit.sn&quot;&gt;DIT&lt;&#x2F;a&gt; student asked me to explain to him what was happening in this &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;flask-user-authentication-example&#x2F;src&#x2F;branch&#x2F;master&#x2F;src&#x2F;main&#x2F;utils.py#L7&quot;&gt;piece of code&lt;&#x2F;a&gt;. A function I have written few months ago to check for valid authentication tokens. In this post, I will try to show how decorators in &lt;a href=&quot;https:&#x2F;&#x2F;python.org&quot;&gt;Python&lt;&#x2F;a&gt;, a powerful concept, allows us to apply new functionality without modifying the existing structure of an object. &lt;a href=&quot;https:&#x2F;&#x2F;y.com.sb&#x2F;watch?v=cDk9L72ZkuE&quot;&gt;Music please&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width: 600px&quot; src=&quot;&#x2F;assets&#x2F;decorated.png&quot; alt=&quot;&quot; title=&quot;Somewhere in Africa&quot;&#x2F;&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h1 id=&quot;toc&quot;&gt;TOC:&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;decor&#x2F;#f&quot;&gt;1 A function doing one thing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;decor&#x2F;#g&quot;&gt;2 A decorator, modifying the behaviour of the function&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;decor&#x2F;#h&quot;&gt;3 A decorator should keep important informations&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;decor&#x2F;#i&quot;&gt;4 A decorator should receive a flexible number of argument&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;decor&#x2F;#j&quot;&gt;5 A decorator can also have parameters&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;decor&#x2F;#k&quot;&gt;6 We are still able to access the decorated function&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;decor&#x2F;#l&quot;&gt;7 An interesting example&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;decor&#x2F;#m&quot;&gt;8 Even more interesting, how decorators are used elsewhere&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;h1 id=&quot;f&quot;&gt;1. A function:&lt;&#x2F;h1&gt;
&lt;p&gt;Let&#x27;s suppose we want to join 2 paths:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;pathlib &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;Path
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;]: a = Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;]: a
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;foo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;]: b = Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;bar&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;]: a.joinpath(b)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;foo&#x2F;bar&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;]: 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s suppose we usually combine 2 paths together. So much that we created a function for that purpose:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;]: path_t = str | Path
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;22&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;jp(path1: path_t, path2: path_t) -&amp;gt; path_t:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;Join 2 paths together&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;isinstance(path1, str):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         path1 = Path(path1)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;path1.joinpath(path2)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt;]: jp(b, a)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;bar&#x2F;foo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;]: jp(a, b)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;foo&#x2F;bar&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;25&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;corge&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, a)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;25&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;corge&#x2F;foo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;26&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;corge&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;qux&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;26&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;corge&#x2F;qux&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;g&quot;&gt;2. A decorator modifying the behaviour of the function:&lt;&#x2F;h1&gt;
&lt;p&gt;While it may seem confusing at first, a decorator is really just &lt;em&gt;a function that takes a function and returns a function&lt;&#x2F;em&gt;. Let me explain.&lt;&#x2F;p&gt;
&lt;p&gt;Suppose we usually combine our home path with another path. Let&#x27;s suppose the first parameter is often our home path. Let&#x27;s suppose we can&#x27;t modify the original function. Python functions are &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;First-class_citizen&quot;&gt;first-class citizens&lt;&#x2F;a&gt;. That means:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;We can pass a function as an argument of another function.&lt;&#x2F;li&gt;
&lt;li&gt;We can assign a function to a variable.&lt;&#x2F;li&gt;
&lt;li&gt;We can return a function as a value from another function.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;38&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;homeprefix(func: Callable[[path_t, path_t], path_t]) -&amp;gt; Callable[[path_t], path_t]:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;wrapper(m: path_t) -&amp;gt; path_t:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A wrapper that takes one parameter.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;func(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;home&#x2F;nsukami&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, m)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;wrapper
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;39&lt;&#x2F;span&gt;&lt;span&gt;]: f = homeprefix(jp)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;40&lt;&#x2F;span&gt;&lt;span&gt;]: f(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;bar&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;40&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;bar&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;41&lt;&#x2F;span&gt;&lt;span&gt;]: f(b)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;41&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;bar&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;42&lt;&#x2F;span&gt;&lt;span&gt;]: f(a)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;42&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;foo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;43&lt;&#x2F;span&gt;&lt;span&gt;]: f(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;corge&#x2F;qux&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;43&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;corge&#x2F;qux&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;44&lt;&#x2F;span&gt;&lt;span&gt;]: f(Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;spam&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;44&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;spam&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;45&lt;&#x2F;span&gt;&lt;span&gt;]: 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As strange as it may seems, we could have done the following:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;45&lt;&#x2F;span&gt;&lt;span&gt;]: jp = homeprefix(jp) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# there is an alternative syntax
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;46&lt;&#x2F;span&gt;&lt;span&gt;]: jp(a)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;46&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;foo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;47&lt;&#x2F;span&gt;&lt;span&gt;]: jp(b)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;47&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;bar&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;48&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foobar&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;48&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;foobar&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;49&lt;&#x2F;span&gt;&lt;span&gt;]: jp(Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;corge&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;49&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;corge&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;50&lt;&#x2F;span&gt;&lt;span&gt;]: 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Instead of &lt;code&gt;jp = homeprefix(jp)&lt;&#x2F;code&gt; we could use the following syntax which better vehicle our intent: &lt;strong&gt;modifying the behaviour of an existing function&lt;&#x2F;strong&gt;. Simply put: &lt;strong&gt;decorating&lt;&#x2F;strong&gt; our original function:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;50&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;homeprefix(func):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;wrapper(m):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A function that takes one parameter.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;func(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;home&#x2F;nsukami&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, m)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;wrapper
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;51&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;homeprefix &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# here we are, decorating jp function 
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;jp(path1: path_t, path2: path_t) -&amp;gt; path_t:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;Join 2 paths together&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;isinstance(path1, str):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         path1 = Path(path1)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;path1.joinpath(path2)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;52&lt;&#x2F;span&gt;&lt;span&gt;]: jp(Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;corge&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;52&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;corge&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;53&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;corge&#x2F;qux&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;53&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;corge&#x2F;qux&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;54&lt;&#x2F;span&gt;&lt;span&gt;]: jp(a)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;54&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;foo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;55&lt;&#x2F;span&gt;&lt;span&gt;]: jp(b)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;55&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;bar&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;56&lt;&#x2F;span&gt;&lt;span&gt;]: 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;h&quot;&gt;3. A decorator should keep important informations:&lt;&#x2F;h1&gt;
&lt;p&gt;Now we have another problem. Because we are literally replacing one function with another, we&#x27;re also losing important informations like the docstring and the name:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;61&lt;&#x2F;span&gt;&lt;span&gt;]: ?jp
&lt;&#x2F;span&gt;&lt;span&gt;Signature: jp(m)
&lt;&#x2F;span&gt;&lt;span&gt;Docstring: A function that takes one parameter.
&lt;&#x2F;span&gt;&lt;span&gt;File:      ~&#x2F;GIT&#x2F;nskm2&#x2F;&amp;lt;ipython-input-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;59&lt;&#x2F;span&gt;&lt;span&gt;-b4f67b1e800d&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;Type:      function
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;62&lt;&#x2F;span&gt;&lt;span&gt;]: jp.__name__
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;62&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;wrapper&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;63&lt;&#x2F;span&gt;&lt;span&gt;]: 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s the reason we have &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;functools.html#functools.wraps&quot;&gt;functools.wraps&lt;&#x2F;a&gt;. &lt;code&gt;Wraps&lt;&#x2F;code&gt; takes the decorated function and adds the functionality of copying over the function name, docstring, arguments list, etc to &lt;strong&gt;the returned function&lt;&#x2F;strong&gt;. And since wraps is itself a decorator:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;63&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;functools &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;wraps
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;64&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;homeprefix(func):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;wraps(func)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;wrapper(m):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A function that takes one parameter.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;func(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;home&#x2F;nsukami&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, m)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;wrapper
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;65&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;homeprefix
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;jp(path1: path_t, path2: path_t) -&amp;gt; path_t:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A function that join 2 paths together.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;isinstance(path1, str):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         path1 = Path(path1)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;path1.joinpath(path2)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;66&lt;&#x2F;span&gt;&lt;span&gt;]: ?jp
&lt;&#x2F;span&gt;&lt;span&gt;Signature: jp(path1: str | pathlib.Path, path2: str | pathlib.Path) -&amp;gt; str | pathlib.Path
&lt;&#x2F;span&gt;&lt;span&gt;Docstring: A function that join &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span&gt;paths together.
&lt;&#x2F;span&gt;&lt;span&gt;File:      ~&#x2F;GIT&#x2F;nskm2&#x2F;&amp;lt;ipython-input-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;65&lt;&#x2F;span&gt;&lt;span&gt;-1703cd8a40dc&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;Type:      function
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;67&lt;&#x2F;span&gt;&lt;span&gt;]: jp.__name__
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;67&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;jp&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;68&lt;&#x2F;span&gt;&lt;span&gt;]: 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;i&quot;&gt;4. A decorator should receive a flexible number of argument:&lt;&#x2F;h1&gt;
&lt;p&gt;Now, let&#x27;s suppose our original function can take many arguments:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;101&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;jp(*args: path_t) -&amp;gt; path_t:
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A function that join many paths together.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;args:
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         path1 = Path(args[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;path1.joinpath(*args[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;:])
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;raise &lt;&#x2F;span&gt;&lt;span&gt;ValueError(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;args should be longer&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;102&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;bac&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;abc&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;102&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;bac&#x2F;abc&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;103&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;bac&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;103&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;bac&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;104&lt;&#x2F;span&gt;&lt;span&gt;]: jp(Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;abc&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;), Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;bar&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;104&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;abc&#x2F;foo&#x2F;bar&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The previous decorator is not flexible enough because the returned function can&#x27;t take more than 1 parameter:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;106&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;homeprefix(func):
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;wraps(func)
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;wrapper(m):
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A function that takes one parameter.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;func(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;home&#x2F;nsukami&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, m)
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;wrapper
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;107&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;homeprefix
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;jp(*args: path_t) -&amp;gt; path_t:
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A function that join many paths together.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;args:
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         path1 = Path(args[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;path1.joinpath(*args[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;:])
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;raise &lt;&#x2F;span&gt;&lt;span&gt;ValueError(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;args should be longer&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;108&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;a&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;108&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;a&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;109&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;a&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;b&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;---------------------------------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt;TypeError                                 Traceback (most recent call last)
&lt;&#x2F;span&gt;&lt;span&gt;Cell In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;109&lt;&#x2F;span&gt;&lt;span&gt;], line &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span&gt;----&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span&gt;jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;a&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;b&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;TypeError: jp() takes &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span&gt;positional argument but &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span&gt;were given
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;110&lt;&#x2F;span&gt;&lt;span&gt;]: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s rewrite our decorator so that the returned function can take an infinte number or arguments:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;113&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;homeprefix(func):
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;wraps(func)
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;wrapper(*args):  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# here is our update: using *args 
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;func(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;home&#x2F;nsukami&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;args)
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;wrapper
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;114&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;homeprefix
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;jp(*args: path_t) -&amp;gt; path_t:
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A function that join many paths together.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;args:
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         path1 = Path(args[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;path1.joinpath(*args[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;:])
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;raise &lt;&#x2F;span&gt;&lt;span&gt;ValueError(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;args should be longer&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;115&lt;&#x2F;span&gt;&lt;span&gt;]: jp()
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;115&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;116&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;b&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;c&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;d&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;116&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;b&#x2F;c&#x2F;d&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;117&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;b&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;c&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;d&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;117&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;b&#x2F;c&#x2F;d&#x2F;foo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;118&lt;&#x2F;span&gt;&lt;span&gt;]: jp(Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;), Path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;bar&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;118&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;foo&#x2F;bar&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;119&lt;&#x2F;span&gt;&lt;span&gt;]: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With the help of the special parameters *args and **kwargs, decorators become more generic. That way if we need the same kind of decorator in different functions with different arguments, we can write just one decorator. In general, a decorator is written like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;decorator(func):
&lt;&#x2F;span&gt;&lt;span&gt;    @wraps(func)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;wrapper(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;args, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span&gt;kwargs):
&lt;&#x2F;span&gt;&lt;span&gt;        func(*args, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span&gt;kwargs)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;wrapper
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;j&quot;&gt;5. A decorator can also have parameters:&lt;&#x2F;h1&gt;
&lt;p&gt;Let&#x27;s suppose people using the decorator want to be able to set what should the prefix used as the first parameter of our jp function. Let&#x27;s suppose we want the decorator to receive one parameter, which is the prefix:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;70&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;homeprefix(prefix): &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# this function builds and returns a decorator 
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;outer(func): &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# this function is the decorator 
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;wraps(func)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;inner(*args, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span&gt;kwargs): &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# the function wrapping the original function 
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A function that takes one parameter.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;func(prefix, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;args, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span&gt;kwargs)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;inner
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;outer
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;71&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;homeprefix(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;home&#x2F;nsukami&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;jp(path1: path_t, path2: path_t) -&amp;gt; path_t:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A function that join 2 paths together.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;isinstance(path1, str):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         path1 = Path(path1)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;path1.joinpath(path2)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;72&lt;&#x2F;span&gt;&lt;span&gt;]: jp(a)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;72&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;foo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;73&lt;&#x2F;span&gt;&lt;span&gt;]: jp(b)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;73&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;bar&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;74&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;corge&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;74&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;corge&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;75&lt;&#x2F;span&gt;&lt;span&gt;]: 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We understand better what&#x27;s going on when we do this instead:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;75&lt;&#x2F;span&gt;&lt;span&gt;]: decorator = homeprefix(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;home&#x2F;patrick&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# setup a prefix 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;76&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;decorator  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# decorate 
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;jp(path1: path_t, path2: path_t) -&amp;gt; path_t:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A function that join 2 paths together.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;isinstance(path1, str):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:         path1 = Path(path1)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;path1.joinpath(path2)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;77&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;corge&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;77&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;patrick&#x2F;corge&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;78&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;quux&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;78&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;patrick&#x2F;quux&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;79&lt;&#x2F;span&gt;&lt;span&gt;]: 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;k&quot;&gt;6. We are still able to access the decorated function:&lt;&#x2F;h1&gt;
&lt;p&gt;Let&#x27;s suppose for some reason we want to test the function as if it was not decorated. Let&#x27;s suppose we still want to use the underlying function. To achieve that, we&#x27;ll use the &lt;code&gt;__wrapped__&lt;&#x2F;code&gt; attribute (assuming we used the &lt;code&gt;functools.wrap&lt;&#x2F;code&gt; function). &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;functools.html?highlight=__wrapped__&quot;&gt;Somewhere&lt;&#x2F;a&gt; in the documentation, we can read:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The original underlying function is accessible through the &lt;strong&gt;wrapped&lt;&#x2F;strong&gt; attribute. This is useful for introspection, for bypassing the cache, or for rewrapping the function with a different cache.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;127&lt;&#x2F;span&gt;&lt;span&gt;]: jp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;127&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;foo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;128&lt;&#x2F;span&gt;&lt;span&gt;]: jp.__wrapped__(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# original function 
&lt;&#x2F;span&gt;&lt;span&gt;Out[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;128&lt;&#x2F;span&gt;&lt;span&gt;]: PosixPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;foo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;129&lt;&#x2F;span&gt;&lt;span&gt;]: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;l&quot;&gt;7. An interesting example:&lt;&#x2F;h1&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env python3
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;csv
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;sqlite3
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;pathlib
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;functools &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;wraps
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;here = pathlib.Path(__file__)
&lt;&#x2F;span&gt;&lt;span&gt;db = here.parent.parent.parent &#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;sqlite_stuff&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;chinook&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;chinook.db&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;connect(db):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A decorator to connect to an SQLite database and execute a query.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    conn = sqlite3.connect(db)
&lt;&#x2F;span&gt;&lt;span&gt;    conn.isolation_level = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;outer(f):
&lt;&#x2F;span&gt;&lt;span&gt;        @wraps(f)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;inner(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;args, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span&gt;kwargs):
&lt;&#x2F;span&gt;&lt;span&gt;            query = f(*args, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span&gt;kwargs)
&lt;&#x2F;span&gt;&lt;span&gt;            rset = conn.execute(query).fetchall()
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;rset
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;inner
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;outer
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;columns(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;columns, limit=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A decorator to specify what columns should be retrieved.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    cols = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.join(columns)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;outer(f):
&lt;&#x2F;span&gt;&lt;span&gt;        @wraps(f)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;inner(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;args, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span&gt;kwargs):
&lt;&#x2F;span&gt;&lt;span&gt;            query = f(*args, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span&gt;kwargs).split(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;*&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;            start, end = query[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].strip(), query[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;].strip()
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;{start} {cols} {end}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt; limit &lt;&#x2F;span&gt;&lt;span&gt;{limit}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;inner
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;outer
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;as_csv(where=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;.&#x2F;result.csv&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;A decorator to save the result as a csv file.&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;outer(f):
&lt;&#x2F;span&gt;&lt;span&gt;        @wraps(f)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;inner(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;args, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span&gt;kwargs):
&lt;&#x2F;span&gt;&lt;span&gt;            rset = f(*args, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;**&lt;&#x2F;span&gt;&lt;span&gt;kwargs)
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;with &lt;&#x2F;span&gt;&lt;span&gt;open(where, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;w&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, newline=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;dest:
&lt;&#x2F;span&gt;&lt;span&gt;                csv_writer = csv.writer(
&lt;&#x2F;span&gt;&lt;span&gt;                    dest, delimiter=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;,&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, quoting=csv.QUOTE_ALL, lineterminator=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\r\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                )
&lt;&#x2F;span&gt;&lt;span&gt;                csv_writer.writerows(rset)
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;len(rset)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;inner
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;outer
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;###
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@as_csv()
&lt;&#x2F;span&gt;&lt;span&gt;@connect(db)
&lt;&#x2F;span&gt;&lt;span&gt;@columns(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;title&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;artistId&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;run(table=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;albums&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    query = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;select * from &lt;&#x2F;span&gt;&lt;span&gt;{table}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;query
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;__name__ == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;__main__&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    print(run())
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;8-even-more-interesting&quot;&gt;8. Even more interesting:&lt;&#x2F;h1&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;sqlite3
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;pathlib
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;functools &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;wraps
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;here = pathlib.Path(__file__)
&lt;&#x2F;span&gt;&lt;span&gt;db = here.parent.parent.parent &#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;sqlite_stuff&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;chinook&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;chinook.db&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;connect(cls):
&lt;&#x2F;span&gt;&lt;span&gt;    conn = sqlite3.connect(db)
&lt;&#x2F;span&gt;&lt;span&gt;    conn.isolation_level = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# sqlite3.IMMEDIATE
&lt;&#x2F;span&gt;&lt;span&gt;    setattr(cls, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;conn&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, conn)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;cls
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;select(cls):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;select(self):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;cls.conn.execute(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;select * from &lt;&#x2F;span&gt;&lt;span&gt;{cls.__name__}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;).fetchall()
&lt;&#x2F;span&gt;&lt;span&gt;    setattr(cls, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;select&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, select)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;cls
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@select
&lt;&#x2F;span&gt;&lt;span&gt;@connect
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Albums:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;__name__ == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;__main__&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    a = Albums()
&lt;&#x2F;span&gt;&lt;span&gt;    print(a.select())
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;m&quot;&gt;8. Even more interesting, how decorators are used elsewhere:&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;cubicweb.org&#x2F;&quot;&gt;Cubicweb&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;cubes&#x2F;api&#x2F;-&#x2F;blob&#x2F;branch&#x2F;default&#x2F;cubicweb_api&#x2F;routes.py#L137&quot;&gt;decorator&lt;&#x2F;a&gt; used to raise an AuthenticationError if no user is detected.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;flask.palletsprojects.com&#x2F;en&#x2F;2.2.x&#x2F;&quot;&gt;Flask&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pallets&#x2F;flask&#x2F;blob&#x2F;afc13b9390ae2e40f4731e815b49edc9ef52ed4b&#x2F;examples&#x2F;tutorial&#x2F;flaskr&#x2F;auth.py#L19&quot;&gt;decorator&lt;&#x2F;a&gt;  that redirects anonymous users to the login page.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;flask.palletsprojects.com&#x2F;en&#x2F;2.2.x&#x2F;patterns&#x2F;viewdecorators&#x2F;#templating-decorator&quot;&gt;Templating decorator&lt;&#x2F;a&gt; invented by the &lt;a href=&quot;https:&#x2F;&#x2F;turbogears.org&#x2F;&quot;&gt;TurboGears&lt;&#x2F;a&gt; guys a while back to automatically render a template.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.djangoproject.com&#x2F;&quot;&gt;Django&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;django&#x2F;django&#x2F;blob&#x2F;main&#x2F;django&#x2F;views&#x2F;decorators&#x2F;http.py&quot;&gt;decorators&lt;&#x2F;a&gt; to manipulate &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;HTTP&#x2F;Headers&quot;&gt;http headers&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;9-more-on-this-topic&quot;&gt;9. More on this topic:&lt;&#x2F;h1&gt;
&lt;p&gt;I hope that you found this post helpful. To learn about this topic, please, browse the following links:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;peps.python.org&#x2F;pep-0318&#x2F;&quot;&gt;PEP 318 – Decorators for Functions and Methods&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;wiki.python.org&#x2F;moin&#x2F;PythonDecoratorLibrary&quot;&gt;PythonDecoratorLibrary&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;functools.html&quot;&gt;functools&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;glossary.html#term-decorator&quot;&gt;decorator&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;sqlite3.html#&quot;&gt;DB-API 2.0 interface for SQLite databases&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;15357776&#x2F;what-is-the-difference-between-functools-wraps-and-update-wrapper&quot;&gt;The difference between wraps and update_wrapper&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.artima.com&#x2F;weblogs&#x2F;viewpost.jsp?thread=241209&quot;&gt;Python Decorators III: A Decorator-Based Build System&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;xkcd.com&#x2F;2692&#x2F;&quot;&gt;Interior decorating&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Test driven interview</title>
        <published>2022-10-16T00:00:00+00:00</published>
        <updated>2022-10-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/tdi/"/>
        <id>https://nskm.xyz/posts/tdi/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/tdi/">&lt;h1 id=&quot;introduction&quot;&gt;Introduction:&lt;&#x2F;h1&gt;
&lt;p&gt;Test Driven Development &lt;em&gt;TDD&lt;&#x2F;em&gt; is a method of implementing software that rely on software requirements being converted to test cases before software is fully developed.&lt;&#x2F;p&gt;
&lt;p&gt;Red, Green and Refactor is the 3 phases of TDD. When followed, this order of steps helps ensure that you have tests for the code you are writing and you are writing only the code that you have to test for.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;context&quot;&gt;Context:&lt;&#x2F;h1&gt;
&lt;p&gt;Let&#x27;s suppose we should implement some requirements. Let&#x27;s suppose all the requirements and specifications are written using unit tests. See this &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&quot;&gt;repository&lt;&#x2F;a&gt;. Our mission is to write enough code to make all the tests pass. Let&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;y.com.sb&#x2F;watch?v=gptoH8rzG14&quot;&gt;dive in&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;toc&quot;&gt;TOC:&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;tdi&#x2F;#setup&quot;&gt;Setup&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;tdi&#x2F;#tests&quot;&gt;Tests&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;#&quot;&gt;Requirements&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;tdi&#x2F;#firstreq&quot;&gt;First requirement&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;tdi&#x2F;#secondreq&quot;&gt;Second requirement&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;tdi&#x2F;#thirdreq&quot;&gt;Third requirement&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;tdi&#x2F;#fourthreq&quot;&gt;Fourth requirement&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;tdi&#x2F;#fifthreq&quot;&gt;Fifth requirement&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;tdi&#x2F;#lastreq&quot;&gt;Last requirement&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt; git create-branch feat-1  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# create a new branch for feature work
&lt;&#x2F;span&gt;&lt;span&gt;Basculement sur la nouvelle branche &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;feat-1&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;(.env) ~&#x2F;GIT&#x2F;interview  (feat-1) 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt; python3.10 -m venv .env  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# create a virtual environment
&lt;&#x2F;span&gt;&lt;span&gt;~&#x2F;GIT&#x2F;interview  (feat-1) 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt; source .env&#x2F;bin&#x2F;activate  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# activate virtual environment
&lt;&#x2F;span&gt;&lt;span&gt;(.env) ~&#x2F;GIT&#x2F;interview  (feat-1) 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt; pip install -r requirements.txt  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# install requirements
&lt;&#x2F;span&gt;&lt;span&gt;Collecting django&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;.2,&amp;gt;=3.1
&lt;&#x2F;span&gt;&lt;span&gt;  Using cached Django-3.1.14-py3-none-any.whl (7.8 MB)
&lt;&#x2F;span&gt;&lt;span&gt;Collecting djangorestframework&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;.13,&amp;gt;=3.12
&lt;&#x2F;span&gt;&lt;span&gt;  Using cached djangorestframework-3.12.4-py3-none-any.whl (957 kB)
&lt;&#x2F;span&gt;&lt;span&gt;Collecting sqlparse&amp;gt;=0.2.2
&lt;&#x2F;span&gt;&lt;span&gt;  Using cached sqlparse-0.4.3-py3-none-any.whl (42 kB)
&lt;&#x2F;span&gt;&lt;span&gt;Collecting asgiref&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;,&amp;gt;=3.2.10
&lt;&#x2F;span&gt;&lt;span&gt;  Using cached asgiref-3.5.2-py3-none-any.whl (22 kB)
&lt;&#x2F;span&gt;&lt;span&gt;Collecting pytz
&lt;&#x2F;span&gt;&lt;span&gt;  Using cached pytz-2022.4-py2.py3-none-any.whl (500 kB)
&lt;&#x2F;span&gt;&lt;span&gt;Installing collected packages: pytz, sqlparse, asgiref, django, djangorestframework
&lt;&#x2F;span&gt;&lt;span&gt;Successfully installed asgiref-3.5.2 django-3.1.14 djangorestframework-3.12.4 pytz-2022.4 sqlparse-0.4.3
&lt;&#x2F;span&gt;&lt;span&gt;WARNING: You are using pip version 22.0.4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span&gt;however, version 22.3 is available.
&lt;&#x2F;span&gt;&lt;span&gt;You should consider upgrading via the &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;GIT&#x2F;interview&#x2F;.env&#x2F;bin&#x2F;python3.10 -m pip install --upgrade pip&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; command.
&lt;&#x2F;span&gt;&lt;span&gt;(.env) ~&#x2F;GIT&#x2F;interview  (feat-1) 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h2 id=&quot;tests&quot;&gt;How to launch tests ?&lt;&#x2F;h2&gt;
&lt;p&gt;According to the &lt;a href=&quot;https:&#x2F;&#x2F;docs.djangoproject.com&#x2F;en&#x2F;4.1&#x2F;topics&#x2F;testing&#x2F;overview&#x2F;#running-tests&quot;&gt;documentation&lt;&#x2F;a&gt;, we can run tests using the test command of your project&#x27;s manage.py utility. Let&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;eradman.com&#x2F;entrproject&#x2F;&quot;&gt;run that command&lt;&#x2F;a&gt; when any of the Python files changes. We also tell Django to stop running the test suite after first failed test. In a different terminal, let&#x27;s type one of the following commands:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# you can ask git ls-files command to watch for all the python files
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt; git ls-files&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt; -- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;*.py&amp;#39; &amp;#39;:!:*__.py&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span&gt;entr sh -c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;python src&#x2F;manage.py test --failfast --force-color -v 2 src&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# you can ask find command to watch for all the python files
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt; find src -type f -name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;*.py&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; -not -name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;__*&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span&gt;entr sh -c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;python src&#x2F;manage.py test --failfast --force-color -v 2 src&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# the ack command seems more readable
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt; ack -f --python &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span&gt;entr sh -c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;python src&#x2F;manage.py test --failfast --force-color -v 2 src&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;Here is our first error:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;django.db.utils.OperationalError: no such table: inventory_product
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h2 id=&quot;firstreq&quot;&gt;1. First requirements: we need a Product model.&lt;&#x2F;h2&gt;
&lt;p&gt;We need to create a model named Product inside an application named inventory. &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;master&#x2F;src&#x2F;modules&#x2F;inventory&#x2F;tests.py#L12&quot;&gt;Somewhere&lt;&#x2F;a&gt; within the tests file, we can read:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;create_coke(self):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;Product.objects.create(
&lt;&#x2F;span&gt;&lt;span&gt;            description=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;Coca-Cola&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            unit_price=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;500&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            stock=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;10
&lt;&#x2F;span&gt;&lt;span&gt;        )
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;Let&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;feat-1&#x2F;src&#x2F;modules&#x2F;inventory&#x2F;models.py#L4&quot;&gt;open&lt;&#x2F;a&gt; the &lt;code&gt;models.py&lt;&#x2F;code&gt; file and write the following:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.db &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;models
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Product(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;models.Model&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    description = models.CharField(max_length=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    unit_price = models.FloatField()
&lt;&#x2F;span&gt;&lt;span&gt;    stock = models.IntegerField()
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;After running the migration scripts:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt; python src&#x2F;manage.py makemigrations &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;python src&#x2F;manage.py migrate
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;The tests tells us to return an &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;HTTP&#x2F;Status&#x2F;201&quot;&gt;http status 201&lt;&#x2F;a&gt; after Product creation. Right now, we have a 404. We need to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;create a REST API.&lt;&#x2F;li&gt;
&lt;li&gt;we should be able to create a Product via the API.&lt;&#x2F;li&gt;
&lt;li&gt;and the returned http status should be 201 _created.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;=====================================================================&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;FAIL: test_create_product (modules.inventory.tests.ProductTestCase)
&lt;&#x2F;span&gt;&lt;span&gt;----------------------------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt;Traceback (most recent call last):
&lt;&#x2F;span&gt;&lt;span&gt;  File &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;home&#x2F;nsukami&#x2F;GIT&#x2F;interview&#x2F;src&#x2F;modules&#x2F;inventory&#x2F;tests.py&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, line 45, in test_create_product
&lt;&#x2F;span&gt;&lt;span&gt;    self.assertEqual(response.status_code, 201)
&lt;&#x2F;span&gt;&lt;span&gt;AssertionError: 404 != 201
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;----------------------------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt;Ran 1 test in 0.010s
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;FAILED (failures=1)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h2 id=&quot;secondreq&quot;&gt;We need a REST API for managing a Product.&lt;&#x2F;h2&gt;
&lt;p&gt;Another &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;master&#x2F;src&#x2F;modules&#x2F;inventory&#x2F;tests.py#L44&quot;&gt;part&lt;&#x2F;a&gt; of the tests is telling us we need an url named &lt;code&gt;api&#x2F;products&#x2F;&lt;&#x2F;code&gt;. Let&#x27;s create a &lt;a href=&quot;https:&#x2F;&#x2F;www.django-rest-framework.org&#x2F;api-guide&#x2F;serializers&#x2F;#modelserializer&quot;&gt;serializer&lt;&#x2F;a&gt;, a &lt;a href=&quot;https:&#x2F;&#x2F;www.django-rest-framework.org&#x2F;api-guide&#x2F;viewsets&#x2F;#modelviewset&quot;&gt;viewset&lt;&#x2F;a&gt; and a &lt;a href=&quot;https:&#x2F;&#x2F;www.django-rest-framework.org&#x2F;api-guide&#x2F;routers&#x2F;&quot;&gt;router&lt;&#x2F;a&gt;. Here is the code:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# &#x2F;src&#x2F;modules&#x2F;inventory&#x2F;views.py
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;rest_framework &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;serializers  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# type:ignore
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;rest_framework &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;viewsets
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from .&lt;&#x2F;span&gt;&lt;span&gt;models &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;Product
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;ProductSerializer(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;serializers.ModelSerializer&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Meta:
&lt;&#x2F;span&gt;&lt;span&gt;        model = Product
&lt;&#x2F;span&gt;&lt;span&gt;        fields = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;__all__&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;ProductsViewSet(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;viewsets.ModelViewSet&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    queryset = Product.objects.all()
&lt;&#x2F;span&gt;&lt;span&gt;    serializer_class = ProductSerializer
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# &#x2F;src&#x2F;pos&#x2F;urls.py
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.urls &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;path, include
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;rest_framework &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;routers
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;modules.inventory.views &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;ProductsViewSet
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;router = routers.DefaultRouter()
&lt;&#x2F;span&gt;&lt;span&gt;router.register(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;products&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, ProductsViewSet)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;urlpatterns = [
&lt;&#x2F;span&gt;&lt;span&gt;    path(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;api&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, include(router.urls)),
&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;After the changes, we notice some progress. The test tells us that if we attempt to delete a Product, we should receive an &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;HTTP&#x2F;Status&#x2F;405&quot;&gt;http status 405&lt;&#x2F;a&gt; instead of 204. Litteraly, we have been able to delete a Product while it shouldn&#x27;t be allowed:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;=====================================================================&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;FAIL: test_delete_product (modules.inventory.tests.ProductTestCase)
&lt;&#x2F;span&gt;&lt;span&gt;----------------------------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt;Traceback (most recent call last):
&lt;&#x2F;span&gt;&lt;span&gt;  File &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;home&#x2F;nsukami&#x2F;GIT&#x2F;interview&#x2F;src&#x2F;modules&#x2F;inventory&#x2F;tests.py&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, line 142, in test_delete_product
&lt;&#x2F;span&gt;&lt;span&gt;    self.assertEqual(response.status_code, 405)
&lt;&#x2F;span&gt;&lt;span&gt;AssertionError: 204 != 405
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;----------------------------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt;Ran 2 tests in 0.011s
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;FAILED (failures=1)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h2 id=&quot;thirdreq&quot;&gt;A Product cannot be deleted.&lt;&#x2F;h2&gt;
&lt;p&gt;I should have take the time to carefully read all the tests. &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;master&#x2F;src&#x2F;modules&#x2F;inventory&#x2F;tests.py#L139&quot;&gt;Indeed&lt;&#x2F;a&gt;, one of them clearly states that we can&#x27;t delete a Product. Obviously, the ModelViewSet is not a good choice. We should update our viewset in a way that forbids product deletion. The operations: &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;master&#x2F;src&#x2F;modules&#x2F;inventory&#x2F;tests.py#L36&quot;&gt;creating&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;master&#x2F;src&#x2F;modules&#x2F;inventory&#x2F;tests.py#L18&quot;&gt;listing&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;master&#x2F;src&#x2F;modules&#x2F;inventory&#x2F;tests.py#L95&quot;&gt;updating&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;master&#x2F;src&#x2F;modules&#x2F;inventory&#x2F;tests.py#L57&quot;&gt;getting one product&lt;&#x2F;a&gt; should still be permitted. To achieve that, we&#x27;ll use some &lt;a href=&quot;https:&#x2F;&#x2F;www.django-rest-framework.org&#x2F;api-guide&#x2F;generic-views&#x2F;#mixins&quot;&gt;mixins&lt;&#x2F;a&gt; offered by the framework. The product viewset becomes:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;rest_framework &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;viewsets, mixins
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;ProductsViewSet(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;mixins.CreateModelMixin&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;mixins.ListModelMixin&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;mixins.UpdateModelMixin&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;mixins.RetrieveModelMixin&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;viewsets.GenericViewSet&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    queryset = Product.objects.all()
&lt;&#x2F;span&gt;&lt;span&gt;    serializer_class = ProductSerializer
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h3 id=&quot;let-s-commit-what-have-been-done-so-far&quot;&gt;Let&#x27;s commit what have been done so far.&lt;&#x2F;h3&gt;
&lt;p&gt;All the tests related to Product are passing. We can commit and push what we&#x27;ve done so far.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt; git commit -m &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Add Product API&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;[feat-1 a11ffeb] Add Product API
&lt;&#x2F;span&gt;&lt;span&gt; 5 files changed, 76 insertions(+), 6 deletions(-)
&lt;&#x2F;span&gt;&lt;span&gt; create mode 100644 src&#x2F;modules&#x2F;inventory&#x2F;migrations&#x2F;0001_initial.py
&lt;&#x2F;span&gt;&lt;span&gt; rewrite src&#x2F;modules&#x2F;inventory&#x2F;views.py (98%)
&lt;&#x2F;span&gt;&lt;span&gt; create mode 100644 src&#x2F;modules&#x2F;orders&#x2F;migrations&#x2F;0001_initial.py
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt; git push origin feat-1 
&lt;&#x2F;span&gt;&lt;span&gt;Énumération des objets: 25, fait.
&lt;&#x2F;span&gt;&lt;span&gt;Décompte des objets: 100% (24&#x2F;24), fait.
&lt;&#x2F;span&gt;&lt;span&gt;Compression par delta en utilisant jusqu&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;à 4 fils d&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;exécution
&lt;&#x2F;span&gt;&lt;span&gt;Compression des objets: 100% (14&#x2F;14), fait.
&lt;&#x2F;span&gt;&lt;span&gt;Écriture des objets: 100% (14&#x2F;14), 1.80 Kio &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span&gt;1.80 Mio&#x2F;s, fait.
&lt;&#x2F;span&gt;&lt;span&gt;Total 14 (delta 6), réutilisés 0 (delta 0), réutilisés du pack 0
&lt;&#x2F;span&gt;&lt;span&gt;remote: 
&lt;&#x2F;span&gt;&lt;span&gt;remote: Create a new pull request for &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;feat-1&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;remote:   https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;compare&#x2F;master...feat-1
&lt;&#x2F;span&gt;&lt;span&gt;remote: 
&lt;&#x2F;span&gt;&lt;span&gt;remote: . Processing 1 references
&lt;&#x2F;span&gt;&lt;span&gt;remote: Processed 1 references in total
&lt;&#x2F;span&gt;&lt;span&gt;To https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview.git
&lt;&#x2F;span&gt;&lt;span&gt; * &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;new branch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;      feat-1 -&amp;gt; feat-1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
  &lt;img style=&quot;display: block; margin: 0 auto; width:100; height:100&quot; src=&quot;&#x2F;images&#x2F;ofcourse.gif&quot; alt=&quot;Of course&quot; title=&quot;Of course&quot;&#x2F;&gt;
&lt;h2 id=&quot;fourthreq&quot;&gt;We need another model named Order.&lt;&#x2F;h2&gt;
&lt;p&gt;All the tests located in the &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;master&#x2F;src&#x2F;modules&#x2F;inventory&#x2F;tests.py&quot;&gt;inventory&lt;&#x2F;a&gt; application are passing. This is why we decided to commit and push. There is one test currently failing, it it located inside the &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;master&#x2F;src&#x2F;modules&#x2F;orders&#x2F;tests.py&quot;&gt;orders&lt;&#x2F;a&gt; application. The test tells us we need to create a model named Order:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;=====================================================================&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;FAIL: test_create_order (modules.orders.tests.OrdersTestCase)
&lt;&#x2F;span&gt;&lt;span&gt;----------------------------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt;Traceback (most recent call last):
&lt;&#x2F;span&gt;&lt;span&gt;  File &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;home&#x2F;nsukami&#x2F;GIT&#x2F;interview&#x2F;src&#x2F;modules&#x2F;orders&#x2F;tests.py&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, line 87, in test_create_order
&lt;&#x2F;span&gt;&lt;span&gt;    self.assertEqual(response.status_code, 201)
&lt;&#x2F;span&gt;&lt;span&gt;AssertionError: 404 != 201
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;----------------------------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt;Ran 7 tests in 0.054s
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;FAILED (failures=1)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;Let&#x27;s continue reading the tests. &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;feat-1&#x2F;src&#x2F;modules&#x2F;orders&#x2F;tests.py#L90&quot;&gt;Line 90&lt;&#x2F;a&gt;, we read that an item should have 4 attributes: &lt;code&gt;description, quantity, unit_price, total&lt;&#x2F;code&gt;. We also read that an Order has 2 attributes: &lt;code&gt;items&lt;&#x2F;code&gt; and &lt;code&gt;total&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;order = Order.objects.get()
&lt;&#x2F;span&gt;&lt;span&gt;expected = {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;id&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: order.id,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;items&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [
&lt;&#x2F;span&gt;&lt;span&gt;        {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;description&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;Coca-Cola&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;quantity&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;unit_price&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;500&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;total&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;500&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        },
&lt;&#x2F;span&gt;&lt;span&gt;        {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;description&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;Potato Chips&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;quantity&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;unit_price&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;total&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2000&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    ],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;total&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2500&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So, our models may look like the following:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Order(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;models.Model&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    @property
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;total(self):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# this field is just a sum, depending on all the items in the current Order
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;sum([x.total &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;self.items.all()])
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;OrderItem(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;models.Model&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    order = models.ForeignKey(Order, related_name=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;items&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, on_delete=models.CASCADE)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# For being able to retrieve the description and the unit_price fields ?
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Should I add Product as a foreign key ? 
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Should I duplicate the fields ?
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    @property
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;total(self):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# the total is obviouly a property that will be calculated 
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# based on the number of items in the Order &amp;amp; the unit price for each item 
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;float(self.unit_price * self.quantity)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h2 id=&quot;fifthreq&quot;&gt;We should be able to update the stock depending on the number of items ordered:&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;feat-1&#x2F;src&#x2F;modules&#x2F;orders&#x2F;tests.py#L114&quot;&gt;Line 114&lt;&#x2F;a&gt; of the tests tells us, a Product should have a method to refresh its stock:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;pyhon&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-pyhon &quot;&gt;&lt;code class=&quot;language-pyhon&quot; data-lang=&quot;pyhon&quot;&gt;&lt;span&gt;self.chips.refresh_from_db()
&lt;&#x2F;span&gt;&lt;span&gt;self.assertEqual(self.chips.stock, 8)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s update our Product model and add the new method. This method will substract the number of Product ordered from the current stock:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.db &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;models
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Product(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;models.Model&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    description = models.CharField(max_length=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    unit_price = models.FloatField()
&lt;&#x2F;span&gt;&lt;span&gt;    stock = models.IntegerField()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;refresh_from_db(self):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;modules.orders.models &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;OrderItem
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        self.stock = self.stock - sum(
&lt;&#x2F;span&gt;&lt;span&gt;            oi.quantity &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;oi &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;OrderItem.objects.filter(id=self.id)
&lt;&#x2F;span&gt;&lt;span&gt;        )
&lt;&#x2F;span&gt;&lt;span&gt;        self.save()
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h2 id=&quot;lastreq&quot;&gt;We should be able to update a Product without modifiying already made Orders:&lt;&#x2F;h2&gt;
&lt;p&gt;After reading the &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;feat-1&#x2F;src&#x2F;modules&#x2F;orders&#x2F;tests.py#L141&quot;&gt;Line 141&lt;&#x2F;a&gt;, we know that the fields &lt;code&gt;description and unit_price&lt;&#x2F;code&gt; will be duplicated inside the OrderItem model. During the OrderItem creation, we should copy those fields from the Product model. This task will be achieved using our serializers:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;ItemSerializer(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;serializers.ModelSerializer&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    quantity = serializers.IntegerField(required=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    unit_price = serializers.FloatField(required=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    description = serializers.CharField(required=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Meta:
&lt;&#x2F;span&gt;&lt;span&gt;        model = OrderItem
&lt;&#x2F;span&gt;&lt;span&gt;        fields = [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;description&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;quantity&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;unit_price&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;total&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;OrderSerializer(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;serializers.ModelSerializer&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    items = ItemSerializer(many=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;create(self, validated_data):
&lt;&#x2F;span&gt;&lt;span&gt;        order = Order.objects.create()
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# I want to be able to access the id, the id represent the Product id
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# So, I&amp;#39;m using initial_data instead of validated_data
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# I&amp;#39;ll need to find a proper way
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;item_data &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;self.initial_data[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;items&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]:
&lt;&#x2F;span&gt;&lt;span&gt;            product = Product.objects.get(id=item_data[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;id&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;            OrderItem.objects.create(
&lt;&#x2F;span&gt;&lt;span&gt;                id=product.id,
&lt;&#x2F;span&gt;&lt;span&gt;                order=order,
&lt;&#x2F;span&gt;&lt;span&gt;                description=product.description,
&lt;&#x2F;span&gt;&lt;span&gt;                unit_price=product.unit_price,
&lt;&#x2F;span&gt;&lt;span&gt;                quantity=item_data[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;quantity&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;            )
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;order
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Meta:
&lt;&#x2F;span&gt;&lt;span&gt;        model = Order
&lt;&#x2F;span&gt;&lt;span&gt;        fields = [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;id&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;items&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;total&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;OrdersViewSet(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;mixins.CreateModelMixin&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;mixins.ListModelMixin&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;mixins.RetrieveModelMixin&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;viewsets.GenericViewSet&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    queryset = Order.objects.all()
&lt;&#x2F;span&gt;&lt;span&gt;    serializer_class = OrderSerializer
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion:&lt;&#x2F;h1&gt;
&lt;p&gt;It&#x27;s been a long time since I&#x27;ve written Django and DRF code. I really enjoyed the exercise. The final result can be found &lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;nsukami&#x2F;interview&#x2F;src&#x2F;branch&#x2F;feat-1&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt; python src&#x2F;manage.py test src --failfast
&lt;&#x2F;span&gt;&lt;span&gt;Creating test database for alias &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;default&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;System check identified no issues (0 silenced).
&lt;&#x2F;span&gt;&lt;span&gt;............
&lt;&#x2F;span&gt;&lt;span&gt;----------------------------------------------------------------------
&lt;&#x2F;span&gt;&lt;span&gt;Ran 12 tests in 0.093s
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;OK
&lt;&#x2F;span&gt;&lt;span&gt;Destroying test database for alias &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;default&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h1 id=&quot;while-i-still-have-your-attention&quot;&gt;While I still have your attention:&lt;&#x2F;h1&gt;
&lt;p&gt;A &lt;a href=&quot;https:&#x2F;&#x2F;djangochat.com&#x2F;episodes&#x2F;django-unicorn-adam-hill&quot;&gt;conversation&lt;&#x2F;a&gt; with Adam Hill about writing software, the perfect settings file set up, and more. Adam is a software engineer at The Motley Fool and the author of multiple open source packages including &lt;a href=&quot;https:&#x2F;&#x2F;www.django-unicorn.com&#x2F;&quot;&gt;Django Unicorn&lt;&#x2F;a&gt;.
&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The videos for the &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=0kOLsFQGxyk&amp;amp;list=PLY_che_OEsX3eIKKLUKvQXfVJhCHYWATM&quot;&gt;DjangoCon Europe 2022&lt;&#x2F;a&gt; are available. Can someone tell me please when the &lt;a href=&quot;https:&#x2F;&#x2F;www.djangoproject.com&#x2F;weblog&#x2F;2019&#x2F;nov&#x2F;18&#x2F;introducing-djangocon-africa&#x2F;&quot;&gt;DjangoCon Africa&lt;&#x2F;a&gt; event will be held ? So I can prepare myself ?&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h1 id=&quot;more-on-the-topic&quot;&gt;More on the topic:&lt;&#x2F;h1&gt;
&lt;p&gt;I really hope you have learned something. To dive even more deeper in the topic, let me please recommend the following links:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;xkcd.com&#x2F;125&#x2F;&quot;&gt;Marketing interview&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Test-driven_development&quot;&gt;Test Driven Development&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;unittest.html&quot;&gt;Unit testing framework&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Learn&#x2F;Server-side&#x2F;Django&#x2F;Testing&quot;&gt;Testing a Django web application&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;test-driven-django-development.readthedocs.io&#x2F;en&#x2F;latest&#x2F;&quot;&gt;Test Driven Web Development with Django&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.djangoproject.com&#x2F;en&#x2F;4.1&#x2F;topics&#x2F;testing&#x2F;overview&#x2F;&quot;&gt;Writing and running tests&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;google.aip.dev&#x2F;&quot;&gt;API Improvement Proposal&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;dsfpa&#x2F;&quot;&gt;Django single file project&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=rR4n-0KYeKQ&quot;&gt;How we write&#x2F;review code in big tech companies&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Linear regression</title>
        <published>2022-07-24T00:00:00+00:00</published>
        <updated>2022-07-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/linreg/"/>
        <id>https://nskm.xyz/posts/linreg/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/linreg/">&lt;p&gt;For the &lt;a href=&quot;https:&#x2F;&#x2F;dit.sn&quot;&gt;Dakar Institute of Technology&lt;&#x2F;a&gt;, I give Python introductory classes. During one of my sessions I was asked about simple linear regression with Python. Let the music &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=adBfKzfemtI&quot;&gt;play&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;disclaimer_not_ds.0eb9147b61b70fa9.jpg&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h1 id=&quot;toc&quot;&gt;TOC:&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#introduction&quot;&gt;Introduction&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#first-solution&quot;&gt;First solution&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#reading-the-data-set&quot;&gt;Reading the data set&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#plotting-the-data-set&quot;&gt;Plotting the data set&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#splitting-the-data-set&quot;&gt;Splitting the data set&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#ordinary-least-squares&quot;&gt;Least squares estimates&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#mean&quot;&gt;Mean&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#variance&quot;&gt;Variance&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#covariance&quot;&gt;Covariance&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#estimates&quot;&gt;Estimates&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#prediction&quot;&gt;Prediction&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#error&quot;&gt;How good is the model&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#final-plot&quot;&gt;Regression line&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#class&quot;&gt;The complete program&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#statistics&quot;&gt;Another solution using the statistics module&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;linreg&#x2F;#code&quot;&gt;Just give me the code please&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;introduction&quot;&gt;Introduction:&lt;&#x2F;h1&gt;
&lt;p&gt;Simple linear regression is a commonly used type of predictive analysis. The idea of regression is to examine if a set of predictor variables do a good job in predicting an outcome variable.&lt;&#x2F;p&gt;
&lt;p&gt;Linear regression models are used in many industries such as healthcare (predicting disease from biological factors), economics (predicting growth), businesses (predicting product sales), etc ...&lt;&#x2F;p&gt;
&lt;p&gt;For simple linear regression, the relationship between the independent variable &lt;strong&gt;x&lt;&#x2F;strong&gt; and the dependent variable &lt;strong&gt;y&lt;&#x2F;strong&gt; is expressed as: &lt;code&gt;y = slope * x + intercept + noise&lt;&#x2F;code&gt;, where:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;slope&lt;&#x2F;em&gt; and &lt;em&gt;intercept&lt;&#x2F;em&gt; are the regression parameters that are estimated&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;noise&lt;&#x2F;em&gt; is the variability of the data (difference between predicted and actual values of &lt;strong&gt;y&lt;&#x2F;strong&gt;).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;h1 id=&quot;first-solution&quot;&gt;First solution:&lt;&#x2F;h1&gt;
&lt;p&gt;Let&#x27;s write a Python program to achieve this task. We&#x27;ll use the following &lt;a href=&quot;&#x2F;assets&#x2F;dataset.txt&quot;&gt;data set&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;reading-the-data-set&quot;&gt;1. Reading the data set:&lt;&#x2F;h2&gt;
&lt;p&gt;To read the data, we&#x27;ll write a function in charge of opening and reading the file containing our data. We assume each line will consist of an int value, followed by a tabulation and a float value. This function will:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;open the file&lt;&#x2F;li&gt;
&lt;li&gt;get all the lines except the first one (the header)&lt;&#x2F;li&gt;
&lt;li&gt;convert first column to int, convert second column to float&lt;&#x2F;li&gt;
&lt;li&gt;return a tuple containing 2 things:&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;read_text(
&lt;&#x2F;span&gt;&lt;span&gt;    filename: t.Union[pathlib.Path, t.AnyStr],
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; t.Tuple[t.Collection[float], t.Collection[float]]:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;with &lt;&#x2F;span&gt;&lt;span&gt;open(filename, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;r&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;f:
&lt;&#x2F;span&gt;&lt;span&gt;        slines = [line.strip().split(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\t&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;line &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;[li &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;li &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;f.readlines()[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;:]]]
&lt;&#x2F;span&gt;&lt;span&gt;        nlines = [(int(x), float(y)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x, y &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;slines]
&lt;&#x2F;span&gt;&lt;span&gt;        X, Y = zip(*nlines)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;X, Y
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;Bonjour&lt;&#x2F;p&gt;
&lt;h2 id=&quot;plotting-the-data-set&quot;&gt;2. Plotting the data set:&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;ll have to do some plotting. The following program is just one we use to setup our &lt;a href=&quot;https:&#x2F;&#x2F;matplotlib.org&#x2F;stable&#x2F;api&#x2F;_as_gen&#x2F;matplotlib.pyplot.subplots.html#matplotlib-pyplot-subplots&quot;&gt;plots&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;ax: mpl.axes.Axes
&lt;&#x2F;span&gt;&lt;span&gt;_, ax = plt.subplots()
&lt;&#x2F;span&gt;&lt;span&gt;ax.set_xlabel(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;X-coordinates&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;ax.set_ylabel(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Y-coordinates &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;ax.set_title(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Graphical representation of our points&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;ax.grid(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;The first step in finding a linear regression equation is to determine if there is a relationship between the two variables. To determine if there is a relationship between x and y we can scatter plot the data set.&lt;&#x2F;p&gt;
&lt;p&gt;Scatter plots are used to observe relationships between variables. We&#x27;ll need one function to do a scatter plot: put dots on our graph and see each individual data point.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;scatter_plot(
&lt;&#x2F;span&gt;&lt;span&gt;    x: t.Collection[float], y: t.Collection[float], ax: mpl.axes.Axes
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    ax.scatter(x, y, color=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;red&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Using this function with our &lt;a href=&quot;&#x2F;assets&#x2F;dataset.txt&quot;&gt;data set&lt;&#x2F;a&gt;, we can see the following chart:&lt;&#x2F;p&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;scatter_plot.04b695a96b3966b3.png&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;We&#x27;ll need a function to draw a line. If we correctly find estimates for our regression parameters (slope and the intercept), we should be able to draw a line that will go through the cloud of data points:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;line_plot(a: int, b: int, ax: mpl.axes.Axes) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    x = [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;130&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;    y = [a * x + b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;x]
&lt;&#x2F;span&gt;&lt;span&gt;    ax.plot(x, y)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h2 id=&quot;splitting-the-data-set&quot;&gt;3. Splitting the data set:&lt;&#x2F;h2&gt;
&lt;p&gt;We don’t want our model to over learn from the data and perform poorly when presented data never seen before. We also need to have a mechanism to assess how well our model is generalizing. Hence, we&#x27;ll need to separate our input data into &lt;em&gt;at least&lt;&#x2F;em&gt; 2 sets: training and testing:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;1-training-data-set&quot;&gt;1. Training data set:&lt;&#x2F;h4&gt;
&lt;p&gt;This is the set of data that will be used only for learning. We will use only one part of the data set to find the best parameters for our model.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;2-testing-data-set&quot;&gt;2. Testing data set:&lt;&#x2F;h4&gt;
&lt;p&gt;It would be best if we evaluate the model with new data that hasn’t been seen by the model before. So we need a set of data used to provide an evaluation without bias of the model that was fitted on the training data set.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s write a function that will split our data. We&#x27;ll keep 80% for the training and 20% for testing. This function will:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;randomly pick 20% of all the indexes in our collection&lt;&#x2F;li&gt;
&lt;li&gt;with those 20% indexes, create a list containing 20% of the collections&lt;&#x2F;li&gt;
&lt;li&gt;from those 20% indexes, create a list containing 80% of the collections&lt;&#x2F;li&gt;
&lt;li&gt;return all the sets&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;split_seq = t.Tuple[
&lt;&#x2F;span&gt;&lt;span&gt;    t.Collection[float], t.Collection[float], t.Collection[float], t.Collection[float]
&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;split_train_test(
&lt;&#x2F;span&gt;&lt;span&gt;    X: t.Collection[float], Y: t.Collection[float], frac: float = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0.2
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; split_seq:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    indexes = list(range(len(X)))
&lt;&#x2F;span&gt;&lt;span&gt;    indexes_test = set(random.sample(indexes, int(frac * len(X))))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# get 20% of Xs based on the indexes, do the same for Ys
&lt;&#x2F;span&gt;&lt;span&gt;    X_test = [n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i, n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;enumerate(X) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;indexes_test]
&lt;&#x2F;span&gt;&lt;span&gt;    Y_test = [n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i, n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;enumerate(Y) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;indexes_test]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# get 80% of Xs based on the indexes, do the same for Ys
&lt;&#x2F;span&gt;&lt;span&gt;    X_train = [n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i, n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;enumerate(X) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;not in &lt;&#x2F;span&gt;&lt;span&gt;indexes_test]
&lt;&#x2F;span&gt;&lt;span&gt;    Y_train = [n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i, n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;enumerate(Y) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;not in &lt;&#x2F;span&gt;&lt;span&gt;indexes_test]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;X_train, X_test, Y_train, Y_test
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s visualize how the 2 sets are rendered in a scatter plot:&lt;&#x2F;p&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;train_test_split.01769c608aeb949a.png&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h1 id=&quot;ordinary-least-squares&quot;&gt;4. Least squares for the slope and the intercept:&lt;&#x2F;h1&gt;
&lt;p&gt;How do we estimate our parameters α and β ? That’s the learning procedure. There are different optimization techniques to implement this part. To determine the optimum values of these two parameters, we should find the line that best fit the data set.&lt;&#x2F;p&gt;
&lt;p&gt;To determine the optimum values of these two parameters, we need to find the &lt;strong&gt;slope&lt;&#x2F;strong&gt; and the &lt;strong&gt;intercept&lt;&#x2F;strong&gt; so that when we sum all the errors between the predicted y values and the observed y values, this sum should be the least possible.&lt;&#x2F;p&gt;
&lt;p&gt;The following chart will show us all the distances (or all the differences, or all the errors) between each point on the dataset and the regression line:&lt;&#x2F;p&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;plotting_OLS.9924776937a70e5c.png&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;Let&#x27;s see how the chart looks like when the parameters are not correctly estimated &lt;em&gt;(the regression line does not &quot;fit&quot; the data set)&lt;&#x2F;em&gt; :&lt;&#x2F;p&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;plotting_bad_OLS.3f873a7960094d1f.png&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;And here is the function used to plot the errors. This function will:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Take the estimated coefficients α and β&lt;&#x2F;li&gt;
&lt;li&gt;Take the list of X and the list of Y&lt;&#x2F;li&gt;
&lt;li&gt;For all points in our data set:
&lt;ul&gt;
&lt;li&gt;predict &lt;code&gt;y&lt;&#x2F;code&gt; based on α and β&lt;&#x2F;li&gt;
&lt;li&gt;draw a dashed line between 2 points: &lt;code&gt;(x, y)&lt;&#x2F;code&gt; and &lt;code&gt;(x, y_pred)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;plot_errors(
&lt;&#x2F;span&gt;&lt;span&gt;    a: float,
&lt;&#x2F;span&gt;&lt;span&gt;    b: float,
&lt;&#x2F;span&gt;&lt;span&gt;    X: t.Collection[float],
&lt;&#x2F;span&gt;&lt;span&gt;    Y: t.Collection[float],
&lt;&#x2F;span&gt;&lt;span&gt;    ax: mpl.axes.Axes,
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x, y &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;zip(X, Y):
&lt;&#x2F;span&gt;&lt;span&gt;        y_pred = a * x + b
&lt;&#x2F;span&gt;&lt;span&gt;        ax.plot([x, x], [y, y_pred], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;bo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, label=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Errors&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, linestyle=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;dashed&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h1 id=&quot;the-total-error-of-this-model-is-the-sum-of-all-the-errors-for-each-point&quot;&gt;The total error of this model is the sum of all the errors for each point:&lt;&#x2F;h1&gt;
&lt;p&gt;We should sum all the errors and look for the least error. Here is the formula:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;The SSE (Sum of Squared Errors) is equal to the sum of the square of Y observed - Y calculated, for all point in the data set.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;lse_formula.1b56ea6087956cd1.png&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;If we do all the correct &lt;a href=&quot;&#x2F;assets&#x2F;Simple_Linear_Regression_Leastsquares.pdf&quot;&gt;algebraic manipulation&lt;&#x2F;a&gt;, we should find that:&lt;&#x2F;p&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;slope_intercept_formulas.4b449a01bfa75294.png&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
&lt;br&gt;
&lt;p&gt;Seeing those formulas, those familiar with statistics already know we&#x27;ll need to define a function to calculate a mean, another function to calculate a variance and a function to calculate a covariance. βeta hat can be defined as Covariance(X, Y) &#x2F; Variance(X).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;mean&quot;&gt;5.1 Mean:&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;em&gt;arithmetic&lt;&#x2F;em&gt; mean, is a measure of central tendency of a finite set of numbers: specifically, the sum of the values divided by the number of values:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;mean(lst: t.Collection[float]) -&amp;gt; float:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;sum(lst) &#x2F; len(lst)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h2 id=&quot;variance&quot;&gt;5.2 Variance:&lt;&#x2F;h2&gt;
&lt;p&gt;The variance  is the measure of the &lt;strong&gt;spread&lt;&#x2F;strong&gt; in a data set. The variance is a measure of how far each number in the data set is from the mean, and thus from every other number in the data set. The higher the variance, the more spread out the variables are.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;variance(lst: t.Collection[float]) -&amp;gt; float:
&lt;&#x2F;span&gt;&lt;span&gt;    m = mean(lst)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;sum([(x - m) ** &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;lst]) &#x2F; len(lst)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;variance: 582.8381391772394
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There is 2 ways to plot the variance. We can do it manually, or we can use a &lt;a href=&quot;https:&#x2F;&#x2F;matplotlib.org&#x2F;stable&#x2F;api&#x2F;_as_gen&#x2F;matplotlib.pyplot.boxplot.html#matplotlib-pyplot-boxplot&quot;&gt;box plot&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;plotting_variance.b71e17d987149681.png&quot; &#x2F;&gt;

&lt;&#x2F;center&gt;
  &lt;img style=&quot;display: block; margin: 0 auto&quot; src=&quot;&#x2F;assets&#x2F;jcvd_split.gif&quot; alt=&quot;Jean-Claude Van Damme split looks like a box plot&quot; title=&quot;Jean-Claude Van Damme split looks like a box plot&quot;&#x2F;&gt;
&lt;br&gt;
&lt;p&gt;Here is the function used to plot the variance:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;plot_variance(
&lt;&#x2F;span&gt;&lt;span&gt;    X: t.Collection[float],
&lt;&#x2F;span&gt;&lt;span&gt;    Y: t.Collection[float],
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    fig: mpl.figure.Figure
&lt;&#x2F;span&gt;&lt;span&gt;    ax: mpl.axes.Axes
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    _, ax = plt.subplots(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    ax[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;].set_xlabel(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;X-coordinates &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    ax[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;].set_ylabel(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Y-coordinates&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    ax[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].set_title(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Graphical representation of variance&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    ax[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;].grid(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# box plot
&lt;&#x2F;span&gt;&lt;span&gt;    ax[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].boxplot([X], vert=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;, showmeans=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# mean line
&lt;&#x2F;span&gt;&lt;span&gt;    ax[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;].axvline(x=mean(X), ymin=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, ymax=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;130&lt;&#x2F;span&gt;&lt;span&gt;, color=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;orange&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# distance from point to mean line
&lt;&#x2F;span&gt;&lt;span&gt;    x_mean = mean(X)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x, y &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;zip(X, Y):
&lt;&#x2F;span&gt;&lt;span&gt;        ax[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;].plot(
&lt;&#x2F;span&gt;&lt;span&gt;            [x, x_mean],
&lt;&#x2F;span&gt;&lt;span&gt;            [y, y],
&lt;&#x2F;span&gt;&lt;span&gt;            marker=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;o&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            color=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;green&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            label=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Mean&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            linestyle=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;dotted&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        )
&lt;&#x2F;span&gt;&lt;span&gt;    plt.show()
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h2 id=&quot;covariance&quot;&gt;5.3 Covariance:&lt;&#x2F;h2&gt;
&lt;p&gt;The covariance is a measure of the relationship between two variables. Covariance is the extent to which the variance in one variable depends on another variable. The higher the covariance, the stronger the relationship.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;covariance(X: t.Sequence[float], Y: t.Sequence[float]) -&amp;gt; float:
&lt;&#x2F;span&gt;&lt;span&gt;    mean_x, mean_y, length_x = mean(X), mean(Y), len(X)
&lt;&#x2F;span&gt;&lt;span&gt;    covar = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0.0
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;range(len(X)):
&lt;&#x2F;span&gt;&lt;span&gt;        covar += (X[i] - mean_x) * (Y[i] - mean_y)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;covar &#x2F; length_x
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;covariance: 2059.003344867359
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h2 id=&quot;estimates&quot;&gt;5.4 Estimates:&lt;&#x2F;h2&gt;
&lt;p&gt;Now that we have a function for calculating the variance and another one for calculating the covariance, we can write a function that will calculate our slope and our intercept using this 2 formulas seen earlier:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;estimate_coefficients(X: t.Collection[float], Y: t.Collection[float]) -&amp;gt; t.Tuple[float, float]:
&lt;&#x2F;span&gt;&lt;span&gt;    b1 = covariance(X, Y) &#x2F; variance(X)
&lt;&#x2F;span&gt;&lt;span&gt;    b0 = mean(Y) - b1 * mean(X)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;b0, b1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h2 id=&quot;prediction&quot;&gt;5.5. Prediction:&lt;&#x2F;h2&gt;
&lt;p&gt;Now that we have extracted our coefficients, let&#x27;s see if we can make a prediction, we&#x27;ll use the testing data set:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;b, a = estimate_coefficients(X_train, Y_train)
&lt;&#x2F;span&gt;&lt;span&gt;Y_predicted = [a * x + b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;X_test]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i, j &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;zip(Y_test, Y_predicted):
&lt;&#x2F;span&gt;&lt;span&gt;    print(i, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\t&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, j)   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# print Y observed in testing set next to Y predicted using our coefficients
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&amp;gt; python3 script.py
&lt;&#x2F;span&gt;&lt;span&gt;392.5 	 389.8167994835544
&lt;&#x2F;span&gt;&lt;span&gt;15.7 	 65.88576964183908
&lt;&#x2F;span&gt;&lt;span&gt;48.8 	 45.426967757099156
&lt;&#x2F;span&gt;&lt;span&gt;113.0 	 99.98377278307227
&lt;&#x2F;span&gt;&lt;span&gt;48.7 	 52.246568385345796
&lt;&#x2F;span&gt;&lt;span&gt;40.3 	 38.607367128852516
&lt;&#x2F;span&gt;&lt;span&gt;59.6 	 76.11517058420904
&lt;&#x2F;span&gt;&lt;span&gt;152.8 	 147.72097718079874
&lt;&#x2F;span&gt;&lt;span&gt;73.4 	 161.360178437292
&lt;&#x2F;span&gt;&lt;span&gt;21.3 	 59.066169013592436
&lt;&#x2F;span&gt;&lt;span&gt;55.6 	 48.83676807122248
&lt;&#x2F;span&gt;&lt;span&gt;194.5 	 123.85237498193551
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;error&quot;&gt;5.6. How good is our model:&lt;&#x2F;h2&gt;
&lt;p&gt;We need to able to measure how good our model is. Among the methods available to achieve this task, let&#x27;s use the most common and the most used: the &lt;a href=&quot;#&quot;&gt;Root mean squared error&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;rmse&quot;&gt;RMSE:&lt;&#x2F;h3&gt;
&lt;p&gt;One way (the most common way?) to assess how well our model fits our data set is to calculate the Root Mean Squared Error. The RMSE is:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the square root&lt;&#x2F;li&gt;
&lt;li&gt;of the mean&lt;&#x2F;li&gt;
&lt;li&gt;of the square of all of the errors&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Let&#x27;s write a function to calculate the RMSE:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;rmse(actual: t.Sequence[float], predicted: t.Sequence[float]) -&amp;gt; float:
&lt;&#x2F;span&gt;&lt;span&gt;    sum_error = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0.0
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;range(len(actual)):
&lt;&#x2F;span&gt;&lt;span&gt;        prediction_error = predicted[i] - actual[i]
&lt;&#x2F;span&gt;&lt;span&gt;        sum_error += prediction_error**&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2
&lt;&#x2F;span&gt;&lt;span&gt;    mean_error = sum_error &#x2F; float(len(actual))
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;math.sqrt(mean_error)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we develop mutliple models, and we want to verify which one performs better:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Calculate the RMSE value for each model&lt;&#x2F;li&gt;
&lt;li&gt;The lower the RMSE value, the better the model.&lt;&#x2F;li&gt;
&lt;li&gt;A RMSE value of 0 indicate a perfect fit.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The data set we&#x27;re working with has a range: [Y_min, Y_max]. This range is important in determining whether a given RMSE value is &quot;low&quot; or &quot;high&quot;. There is no &quot;good&quot; or no &quot;bad&quot; RMSE value. It always depends on the range of the data set we&#x27;re working with.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;normalized-rmse&quot;&gt;Normalized RMSE:&lt;&#x2F;h3&gt;
&lt;p&gt;The NRMSE is the RMSE divided by Y_max - Y_min. The result will be between 0 and 1, where values closer to 0 represent better fitting models. The normalization facilitates the comparison between data sets with different scales:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;rmse(
&lt;&#x2F;span&gt;&lt;span&gt;    actual: t.Sequence[float], predicted: t.Sequence[float]
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; t.Tuple[float, float]:
&lt;&#x2F;span&gt;&lt;span&gt;    mean_error = sum([(predicted[i] - actual[i])**&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;range(len(actual))]) &#x2F; float(len(actual))
&lt;&#x2F;span&gt;&lt;span&gt;    rmse = math.sqrt(mean_error)
&lt;&#x2F;span&gt;&lt;span&gt;    nrmse = rmse &#x2F; (max(predicted) - min(predicted))
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;rmse, nrmse
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt; python3 script.py 
&lt;&#x2F;span&gt;&lt;span&gt;The RMSE is 23.27666203730159
&lt;&#x2F;span&gt;&lt;span&gt;Normalized RMSE is 0.06371542339113609
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;final-plot&quot;&gt;5.7. Regression line:&lt;&#x2F;h2&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;plot_regression_line.156ebbadc8a6d8e7.png&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h1 id=&quot;class&quot;&gt;The complete program:&lt;&#x2F;h1&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;math
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;random
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;requests  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# type:ignore
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;matplotlib &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;mpl  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# type:ignore
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;matplotlib.pyplot &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;plt  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# type:ignore
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;t
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;pathlib
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;dataclasses &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;dataclass, field
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# setup plots
&lt;&#x2F;span&gt;&lt;span&gt;fig: mpl.figure.Figure
&lt;&#x2F;span&gt;&lt;span&gt;ax: mpl.axes.Axes
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;fig, ax = plt.subplots()
&lt;&#x2F;span&gt;&lt;span&gt;ax.set_xlabel(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;X-coordinates &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;ax.set_ylabel(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Y-coordinates&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;ax.set_title(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Graphical representation of our points&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;ax.grid(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;splits = t.Tuple[
&lt;&#x2F;span&gt;&lt;span&gt;    t.Collection[float], t.Collection[float], t.Collection[float], t.Collection[float]
&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@dataclass
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;SimpleLinearRegression:
&lt;&#x2F;span&gt;&lt;span&gt;    filename: t.Union[pathlib.Path, str] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;.&#x2F;dataset.txt&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    __X: t.Collection[float] = field(init=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    __Y: t.Collection[float] = field(init=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    X_train: t.Collection[float] = field(init=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    Y_train: t.Collection[float] = field(init=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    X_test: t.Collection[float] = field(init=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    Y_test: t.Collection[float] = field(init=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;__post_init__(self) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;with &lt;&#x2F;span&gt;&lt;span&gt;open(self.filename, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;r&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;f:
&lt;&#x2F;span&gt;&lt;span&gt;            slines = [
&lt;&#x2F;span&gt;&lt;span&gt;                line.strip().split(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\t&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;line &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;[li &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;li &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;f.readlines()[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;:]]
&lt;&#x2F;span&gt;&lt;span&gt;            ]
&lt;&#x2F;span&gt;&lt;span&gt;            nlines = [(float(x), float(y)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x, y &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;slines]
&lt;&#x2F;span&gt;&lt;span&gt;            self.__X, self.__Y = zip(*nlines)
&lt;&#x2F;span&gt;&lt;span&gt;            self.__split_train_test()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;scatter_plot(self, ax: mpl.axes.Axes, color: str = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;red&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, label=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        ax.scatter(self.__X, self.__Y, color=color, label=label)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;line_plot(self, ax: mpl.axes.Axes) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        b, a = self.estimate_coefficients()
&lt;&#x2F;span&gt;&lt;span&gt;        x = [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;130&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;        y = [a * x + b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;x]
&lt;&#x2F;span&gt;&lt;span&gt;        ax.plot(x, y, color=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;green&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;__mean(self, lst: t.Collection[float]) -&amp;gt; float:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;sum(lst) &#x2F; len(lst)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;__var(self, lst: t.Collection[float]) -&amp;gt; float:
&lt;&#x2F;span&gt;&lt;span&gt;        m = self.__mean(lst)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;sum([(x - m) ** &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;lst]) &#x2F; len(lst)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;__cov(self, X: t.Sequence[float], Y: t.Sequence[float]) -&amp;gt; float:
&lt;&#x2F;span&gt;&lt;span&gt;        mean_x = self.__mean(X)
&lt;&#x2F;span&gt;&lt;span&gt;        mean_y = self.__mean(Y)
&lt;&#x2F;span&gt;&lt;span&gt;        covar = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0.0
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;range(len(X)):
&lt;&#x2F;span&gt;&lt;span&gt;            covar += (X[i] - mean_x) * (Y[i] - mean_y)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;covar &#x2F; len(X)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;__split_train_test(self, frac: float = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0.2&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        indexes = list(range(len(self.__X)))
&lt;&#x2F;span&gt;&lt;span&gt;        indexes_test = set(random.sample(indexes, int(frac * len(self.__X))))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# get 20% of Xs based on the indexes, do the same for Ys
&lt;&#x2F;span&gt;&lt;span&gt;        self.X_test = [n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i, n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;enumerate(self.__X) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;indexes_test]
&lt;&#x2F;span&gt;&lt;span&gt;        self.Y_test = [n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i, n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;enumerate(self.__Y) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;indexes_test]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# get 80% of Xs based on the indexes, do the same for Ys
&lt;&#x2F;span&gt;&lt;span&gt;        self.X_train = [n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i, n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;enumerate(self.__X) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;not in &lt;&#x2F;span&gt;&lt;span&gt;indexes_test]
&lt;&#x2F;span&gt;&lt;span&gt;        self.Y_train = [n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i, n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;enumerate(self.__Y) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;not in &lt;&#x2F;span&gt;&lt;span&gt;indexes_test]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;estimate_coefficients(
&lt;&#x2F;span&gt;&lt;span&gt;        self,
&lt;&#x2F;span&gt;&lt;span&gt;    ) -&amp;gt; t.Tuple[float, float]:
&lt;&#x2F;span&gt;&lt;span&gt;        mean_x, mean_y = self.__mean(self.X_train), self.__mean(self.Y_train)
&lt;&#x2F;span&gt;&lt;span&gt;        b1 = self.__cov(self.X_train, self.Y_train) &#x2F; self.__var(  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# type:ignore
&lt;&#x2F;span&gt;&lt;span&gt;            self.X_train
&lt;&#x2F;span&gt;&lt;span&gt;        )
&lt;&#x2F;span&gt;&lt;span&gt;        b0 = mean_y - b1 * mean_x
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;b0, b1
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;rmse(self) -&amp;gt; t.Tuple[float, float]:
&lt;&#x2F;span&gt;&lt;span&gt;        b, a = self.estimate_coefficients()
&lt;&#x2F;span&gt;&lt;span&gt;        predicted = [a * x + b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;self.X_test]
&lt;&#x2F;span&gt;&lt;span&gt;        actual = self.Y_test
&lt;&#x2F;span&gt;&lt;span&gt;        mean_error = sum(
&lt;&#x2F;span&gt;&lt;span&gt;            [(predicted[i] - actual[i]) ** &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;range(len(actual))]  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# type:ignore
&lt;&#x2F;span&gt;&lt;span&gt;        ) &#x2F; float(
&lt;&#x2F;span&gt;&lt;span&gt;            len(actual)
&lt;&#x2F;span&gt;&lt;span&gt;        )
&lt;&#x2F;span&gt;&lt;span&gt;        rmse = math.sqrt(mean_error)
&lt;&#x2F;span&gt;&lt;span&gt;        nrmse = math.sqrt(mean_error) &#x2F; (max(predicted) - min(predicted))
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;rmse, nrmse
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# program entry point
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;__name__ == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;__main__&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;main() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        model = SimpleLinearRegression()
&lt;&#x2F;span&gt;&lt;span&gt;        model.scatter_plot(ax)
&lt;&#x2F;span&gt;&lt;span&gt;        model.line_plot(ax)
&lt;&#x2F;span&gt;&lt;span&gt;        b, a = model.estimate_coefficients()
&lt;&#x2F;span&gt;&lt;span&gt;        rmse, nrmse = model.rmse()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        print(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;The slope is &lt;&#x2F;span&gt;&lt;span&gt;{a}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;, the intercept is &lt;&#x2F;span&gt;&lt;span&gt;{b}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;        print(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;The RMSE and NRMSE are: &lt;&#x2F;span&gt;&lt;span&gt;{rmse}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt; and &lt;&#x2F;span&gt;&lt;span&gt;{nrmse}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;        plt.show()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    main()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;The slope is 3.426108589853597, the intercept is 20.478117458572427
&lt;&#x2F;span&gt;&lt;span&gt;The RMSE and NRMSE are: 27.82841276749733 and 0.07520791645397
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h1 id=&quot;statistics&quot;&gt;Another solution, using the statistics module:&lt;&#x2F;h1&gt;
&lt;p&gt;Before jumping to big and powerful libraries such as &lt;a href=&quot;https:&#x2F;&#x2F;numpy.org&#x2F;doc&#x2F;stable&#x2F;reference&#x2F;routines.statistics.html&quot;&gt;NumPy&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;docs.scipy.org&#x2F;doc&#x2F;scipy&#x2F;reference&#x2F;stats.html&quot;&gt;SciPy&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pandas-dev&#x2F;pandas&quot;&gt;Pandas&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;raphaelvallat&#x2F;pingouin&quot;&gt;Pingouin&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;statsmodels&#x2F;statsmodels&quot;&gt;Statsmodel&lt;&#x2F;a&gt;, and all the others. We have to notice, Python provides us with a module named &lt;a href=&quot;https:&#x2F;&#x2F;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;statistics.html&quot;&gt;statistics&lt;&#x2F;a&gt;. Even though the statistics module is not intended to be a competitor to the ones listed above, it&#x27;s interesting to see that inside, there is:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;statistics.html#statistics.mean&quot;&gt;mean&lt;&#x2F;a&gt; function&lt;&#x2F;li&gt;
&lt;li&gt;a &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;statistics.html#statistics.variance&quot;&gt;variance&lt;&#x2F;a&gt; function&lt;&#x2F;li&gt;
&lt;li&gt;a &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;statistics.html#statistics.covariance&quot;&gt;covariance&lt;&#x2F;a&gt; function&lt;&#x2F;li&gt;
&lt;li&gt;even a &lt;a href=&quot;https:&#x2F;&#x2F;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;statistics.html#statistics.linear_regression&quot;&gt;linear regression&lt;&#x2F;a&gt; function.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Our program will suddenly become shorter:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;statistics &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;lestat
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# load dataset
&lt;&#x2F;span&gt;&lt;span&gt;X, Y = read_text(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;dataset.txt&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# extract coefficients
&lt;&#x2F;span&gt;&lt;span&gt;a, b = lestat.linear_regression(X, Y)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h1 id=&quot;code&quot;&gt;Source code:&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;c.tenor.com&#x2F;a5n5GalczLsAAAAM&#x2F;relief-phew.gif&quot;&gt;&lt;em&gt;Phew&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;. All the cool devs today will share the source code via a Jupyter notebook stored on Github or on Colab. According to the &lt;a href=&quot;https:&#x2F;&#x2F;sfconservancy.org&#x2F;&quot;&gt;Software Freedom Conservancy&lt;&#x2F;a&gt;, we should all &lt;a href=&quot;https:&#x2F;&#x2F;sfconservancy.org&#x2F;GiveUpGitHub&#x2F;&quot;&gt;Give Up GitHub&lt;&#x2F;a&gt;. And as a free software advocate, I agree with them. The source code can be found &lt;a href=&quot;&#x2F;assets&#x2F;script.py&quot;&gt;here&lt;&#x2F;a&gt; and the data set &lt;a href=&quot;&#x2F;assets&#x2F;dataset.txt&quot;&gt;here&lt;&#x2F;a&gt;. You&#x27;re welcome.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h1 id=&quot;more-on-this-topic&quot;&gt;More on this topic:&lt;&#x2F;h1&gt;
&lt;p&gt;I really hope you&#x27;ve learned something, really. Talking about the whole subject won&#x27;t be possible in this tiny article. To dive deeper and learn even more, let me please recommend the following links:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;pypi.org&#x2F;project&#x2F;datasette&#x2F;&quot;&gt;Datasette&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;matplotlib.org&#x2F;&quot;&gt;Matplotlib&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;xkcd.com&#x2F;378&#x2F;&quot;&gt;Real programmers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.sciencedirect.com&#x2F;topics&#x2F;engineering&#x2F;root-mean-squared-error&quot;&gt;Root-Mean-Squared Error&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;posit.co&#x2F;&quot;&gt;RStudio is becoming Posit&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;scikit-learn.org&#x2F;stable&#x2F;modules&#x2F;generated&#x2F;sklearn.linear_model.LinearRegression.html&quot;&gt;Ordinary least squares Linear Regression with scikit learn&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Wall of Fame</title>
        <published>2022-07-04T00:00:00+00:00</published>
        <updated>2022-07-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/wall/"/>
        <id>https://nskm.xyz/wall/</id>
        
        <content type="html" xml:base="https://nskm.xyz/wall/">&lt;p&gt;Here it is, the Wall of Fame.&lt;&#x2F;p&gt;
&lt;div&gt;

    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_a_core_dev_followed_me.jpg&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_a_core_dev_followed_me.8e8245579593b0f8.jpg&quot; alt=&quot;foo&quot; title=&quot;a core dev followed me&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_ashwinvis_enjoyed_my_mypy_article.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_ashwinvis_enjoyed_my_mypy_article.574457f975fea21d.png&quot; alt=&quot;foo&quot; title=&quot;ashwinvis enjoyed my mypy article&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Bash_aliases_and_functions.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Bash_aliases_and_functions.3ca5c8e249e0a455.png&quot; alt=&quot;foo&quot; title=&quot;Bash aliases and functions&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Current_status.jpg&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Current_status.d406aaba585359c1.jpg&quot; alt=&quot;foo&quot; title=&quot;Current status&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_customized_Hugo_hermit_theme.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_customized_Hugo_hermit_theme.8ae1ad770e1b0734.png&quot; alt=&quot;foo&quot; title=&quot;customized Hugo hermit theme&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Django_donator.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Django_donator.bef05b8e403fe16a.png&quot; alt=&quot;foo&quot; title=&quot;Django donator&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Djibril_being_grateful_to_me.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Djibril_being_grateful_to_me.85ea81234fa4fcbd.png&quot; alt=&quot;foo&quot; title=&quot;Djibril being grateful to me&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_donkirby_reusing_my_work.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_donkirby_reusing_my_work.b8f37fd3c4e90ef5.png&quot; alt=&quot;foo&quot; title=&quot;donkirby reusing my work&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Dont_introduce_yourself.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Dont_introduce_yourself.6772b572b264769c.png&quot; alt=&quot;foo&quot; title=&quot;Dont introduce yourself&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Efficacite_de_la_creation.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Efficacite_de_la_creation.f366ac3a8200fb9d.png&quot; alt=&quot;foo&quot; title=&quot;Efficacite de la creation&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Emacs_massive_find_replace.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Emacs_massive_find_replace.1e9e80f82f0c3d1c.png&quot; alt=&quot;foo&quot; title=&quot;Emacs massive find replace&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Exploring_PyPolars.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Exploring_PyPolars.41f3d0e4b395fc6d.png&quot; alt=&quot;foo&quot; title=&quot;Exploring PyPolars&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Figthing_against_Mypy.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Figthing_against_Mypy.de7f548ae09b45f4.png&quot; alt=&quot;foo&quot; title=&quot;Figthing against Mypy&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_First_day_on_Mastodon.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_First_day_on_Mastodon.38d18dd00f5e2a42.png&quot; alt=&quot;foo&quot; title=&quot;First day on Mastodon&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Gandi_API.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Gandi_API.2e4372b1327a02b5.png&quot; alt=&quot;foo&quot; title=&quot;Gandi API&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Gandi_API_again.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Gandi_API_again.847b2968e784e92c.png&quot; alt=&quot;foo&quot; title=&quot;Gandi API again&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Gnus_once_upon_a_time.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Gnus_once_upon_a_time.8dac3ebd9b08dca3.png&quot; alt=&quot;foo&quot; title=&quot;Gnus once upon a time&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Hercules.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Hercules.8a20d66567588c01.png&quot; alt=&quot;foo&quot; title=&quot;Hercules&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_I_am_a_libertarian_leftist.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_I_am_a_libertarian_leftist.e9c7235b551f63e7.png&quot; alt=&quot;foo&quot; title=&quot;I am a libertarian leftist&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Julien_Palard_reacted_to_my_toot.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Julien_Palard_reacted_to_my_toot.02c9b51bdf84c818.png&quot; alt=&quot;foo&quot; title=&quot;Julien Palard reacted to my toot&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_kingbuzzman_reused_my_work.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_kingbuzzman_reused_my_work.8584a39a6c706df8.png&quot; alt=&quot;foo&quot; title=&quot;kingbuzzman reused my work&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Konami_code.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Konami_code.6edf6e64efe8be15.png&quot; alt=&quot;foo&quot; title=&quot;Konami code&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Logilab_thanks_me_for_my_work.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Logilab_thanks_me_for_my_work.374fce72f1aadf39.png&quot; alt=&quot;foo&quot; title=&quot;Logilab thanks me for my work&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_me.jpg&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_me.4e54225d2209fa39.jpg&quot; alt=&quot;foo&quot; title=&quot;me&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Mercurial_aliases.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Mercurial_aliases.7e0820558947e9a7.png&quot; alt=&quot;foo&quot; title=&quot;Mercurial aliases&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Never_knew_I_was_one_of_the_creators_of_Python_Idle.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Never_knew_I_was_one_of_the_creators_of_Python_Idle.538d0f244bd173d0.png&quot; alt=&quot;foo&quot; title=&quot;Never knew I was one of the creators of Python Idle&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Playing_with_Delta_Chat.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Playing_with_Delta_Chat.a3710e84afed5bb2.png&quot; alt=&quot;foo&quot; title=&quot;Playing with Delta Chat&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Playing_with_Git_hooks.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Playing_with_Git_hooks.d0e265d8ee5507c9.png&quot; alt=&quot;foo&quot; title=&quot;Playing with Git hooks&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Playing_with_Quarto.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Playing_with_Quarto.b1953381cb548b9a.png&quot; alt=&quot;foo&quot; title=&quot;Playing with Quarto&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_PR_accepted_to_typeshed_repo.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_PR_accepted_to_typeshed_repo.c7b86067ce4b5ac5.png&quot; alt=&quot;foo&quot; title=&quot;PR accepted to typeshed repo&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Proud_Emacs_Stackexchange_User.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Proud_Emacs_Stackexchange_User.c664f068e88bbb13.png&quot; alt=&quot;foo&quot; title=&quot;Proud Emacs Stackexchange User&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Proud_Emacs_user.jpg&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Proud_Emacs_user.4ea7bae1980d4fda.jpg&quot; alt=&quot;foo&quot; title=&quot;Proud Emacs user&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_PSF_member_yes.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_PSF_member_yes.8a574b3de6c0aed4.png&quot; alt=&quot;foo&quot; title=&quot;PSF member yes&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_pycon_africa_speaker.jpg&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_pycon_africa_speaker.9bfe680412266c97.jpg&quot; alt=&quot;foo&quot; title=&quot;pycon africa speaker&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Python_release_meassages_are_the_bests.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Python_release_meassages_are_the_bests.f36dffb844ed6e2f.png&quot; alt=&quot;foo&quot; title=&quot;Python release meassages are the bests&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Python_subprocess_example.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Python_subprocess_example.64a643f6d69895bb.png&quot; alt=&quot;foo&quot; title=&quot;Python subprocess example&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Reading.jpg&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Reading.e1323ecf5a19501c.jpg&quot; alt=&quot;foo&quot; title=&quot;Reading&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Rules_for_a_good_life.jpg&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Rules_for_a_good_life.d6c4185e1ab08970.jpg&quot; alt=&quot;foo&quot; title=&quot;Rules for a good life&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_sqlite_select_as_CSV.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_sqlite_select_as_CSV.1f30c9897fc1bb83.png&quot; alt=&quot;foo&quot; title=&quot;sqlite select as CSV&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Taking_stance.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Taking_stance.a14757f3246d4612.png&quot; alt=&quot;foo&quot; title=&quot;Taking stance&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Time_to_upgrade_distribution.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Time_to_upgrade_distribution.8e5e464c1d4dad81.png&quot; alt=&quot;foo&quot; title=&quot;Time to upgrade distribution&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_When_I_was_dealing_with_Paypox_wtf.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_When_I_was_dealing_with_Paypox_wtf.13ea33a6beb67dd2.png&quot; alt=&quot;foo&quot; title=&quot;When I was dealing with Paypox wtf&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_When_I_was_working_on_Vialegal.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_When_I_was_working_on_Vialegal.a471c4021dd87533.png&quot; alt=&quot;foo&quot; title=&quot;When I was working on Vialegal&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Why_I_dont_use_social.media.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Why_I_dont_use_social.media.a93363674756712b.png&quot; alt=&quot;foo&quot; title=&quot;Why I dont use social.media&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_Yasnippets_to_send_a_resume.png&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_Yasnippets_to_send_a_resume.9f43176f3144c85c.png&quot; alt=&quot;foo&quot; title=&quot;Yasnippets to send a resume&quot;&gt;
    &lt;&#x2F;a&gt;
    


    &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;wof&#x2F;pictures&#x2F;HOF_You_are_your_own_timezone.jpg&quot; target=&quot;_blank&quot;&gt;
      &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;HOF_You_are_your_own_timezone.ebbd3ce55e8bf6ff.jpg&quot; alt=&quot;foo&quot; title=&quot;You are your own timezone&quot;&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Writing</title>
        <published>2022-05-20T00:00:00+00:00</published>
        <updated>2022-05-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/blg/"/>
        <id>https://nskm.xyz/posts/blg/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/blg/">&lt;p&gt;I often receive resumes from people looking for a job and asking me for help. To all of them I always ask: &quot;Do you have a website ?&quot;, &quot;Do you write ?&quot;. And most of the time, the answer is negative.&lt;&#x2F;p&gt;
&lt;p&gt;Writing skills are important because they allow the reader to get their first impression of who is the writer. For example: writing skills displayed in resume, cover letter email communications, website. In my humble opinion, if you&#x27;re looking for a job as a software engineer, you should have a tiny space on the internet. A space in which you write about what you experiment, what you code, what you build.&lt;&#x2F;p&gt;
&lt;p&gt;This article is an attempt to answer, why I think everybody (every software engineer)  should have a website. Or at least, why everybody should write. This article is also &lt;em&gt;kind of&lt;&#x2F;em&gt; a recap of a talk I gave for the &lt;a href=&quot;https:&#x2F;&#x2F;dit.sn&quot;&gt;Dakar Institute of Tecnology&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;wr.45c3c0f8e7026afa.jpg&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
&lt;br&gt;
&lt;br&gt;
&lt;h1 id=&quot;some-reasons-for-you-to-start-writing&quot;&gt;&lt;u&gt;Some reasons for you to start writing: &lt;&#x2F;u&gt;&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;1-improve-your-knowledge-on-a-topic&quot;&gt;&lt;em&gt;1. Improve your knowledge on a topic&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;You&#x27;ll often have to write about subjects that you are not familiar with, so finding quality sources quickly is a skill you&#x27;ll develop. Before you write a single word, you need to do your research about the topic you&#x27;re writing on. The more you do research, the more you find quality sources, the more you improve your knowledge.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-organize-your-thoughts&quot;&gt;&lt;em&gt;2. Organize your thoughts&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;You can write down more than you can easily remember, so that your capacity to consider a number of ideas at the same time is broadened. Once those ideas are written down, you can move them around, change them. You can also reject those that are finally not good enough. You will stay with good, original clearly defined ideas. And you will be able to organize and communicate them easily.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3-share-your-expertise-meet-fellow-specialist-and-grow-your-knowledge&quot;&gt;&lt;em&gt;3. Share your expertise, meet fellow specialist and grow your knowledge&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Knowledge is the only thing that grows when shared. Sharing your knowledge helps you grow your knowledge by doing research, synthesizing multiple and different viewpoints. Sharing your expertise means inviting people to read you, inviting people to a new conversation. A conversation is always an occasion to meet new people and to grow as a human.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;4-make-money&quot;&gt;&lt;em&gt;4. Make money&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Even professions that don&#x27;t focus on writing require written communication skills. The tech industry for example, is more and more looking for people who are able to write. Those writings include things like instruction manuals, user manuals, journal articles, product descriptions, memos, wikis, documentations, etc...&lt;&#x2F;p&gt;
&lt;p&gt;You can have a look :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.indeed.com&#x2F;q-Technical-Writer-jobs.html?vjk=1e9cd66778e25548&quot;&gt;here&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.upwork.com&#x2F;freelance-jobs&#x2F;technical-writing&#x2F;&quot;&gt;then here&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.glassdoor.com&#x2F;Job&#x2F;technical-writer-jobs-SRCH_KO0,16.htm&quot;&gt;here again&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;careers.google.com&#x2F;jobs&#x2F;results&#x2F;93728821645058758-technical-writer-google-cloud&#x2F;?distance=50&amp;amp;q=technical%20writer&quot;&gt;also  here&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;By the way:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;realpython.com&#x2F;write-for-us&#x2F;&quot;&gt;Real Python is hiring&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;lwn.net&#x2F;Articles&#x2F;895695&#x2F;&quot;&gt;LWN is hiring too&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;em&gt;disclaimer: I&#x27;m not paid by anybody to share those job offers&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h1 id=&quot;what-are-the-topic-to-write-about&quot;&gt;&lt;u&gt;What are the topic to write about: &lt;&#x2F;u&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;Coming up with writing inspiration is tough. My advice would be, &lt;strong&gt;in all the cases, always write about something you really like, or something you really enjoy.&lt;&#x2F;strong&gt; As a technical writer, you can write different kinds of articles:&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1-story&quot;&gt;&lt;em&gt;1. Story&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Human beings are interested in stories about people. If your reader knows you a little through your blog, the reader will remember who you are and the reader will be more interested by your technical articles. &lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;ask&quot;&gt;Here&lt;&#x2F;a&gt; you&#x27;ll find different kinds of stories.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-opinion&quot;&gt;&lt;em&gt;2. Opinion&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Giving an opinion is a common way of interacting with other people. Of course you don&#x27;t simply share an opinion, you&#x27;ll also share the compelling and interesting argument that support this opinion. Also, please don&#x27;t spend your time attacking others people or spreading controversial ideas. Here is an &lt;a href=&quot;https:&#x2F;&#x2F;drewdevault.com&#x2F;2019&#x2F;12&#x2F;09&#x2F;Developers-shouldnt-distribute.html&quot;&gt;axample&lt;&#x2F;a&gt; of a shared opinion.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3-how-tos&quot;&gt;&lt;em&gt;3. HOW-TOs&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;An how-to is a document providing detailed and practical step-by-step guide on how to do something. In a precise, step-by-step approach, you should walk your reader through the process. You should make sure your reader can reproduce the same results by following the provided steps.  &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;howto&#x2F;pyporting.html&quot;&gt;Example&lt;&#x2F;a&gt; of an HOWTO.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;4-how-something-work&quot;&gt;&lt;em&gt;4. How something work&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;There are people &lt;em&gt;like me&lt;&#x2F;em&gt; who want to know how almost everything works. This kind of article is suitable when you want to deep dive into a very specific topic. For example, somebody already using Django sessions, may be suddenly wondering how does Django sessions work under the hood ? Here is an &lt;a href=&quot;https:&#x2F;&#x2F;eli.thegreenplace.net&#x2F;2011&#x2F;06&#x2F;24&#x2F;how-django-sessions-work-introduction&quot;&gt;article&lt;&#x2F;a&gt; showing how Django sessions work.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;5-reviews&quot;&gt;&lt;em&gt;5. Reviews&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;You have read, used, tested, played with something. In a review, your attempt will be to write about what was your experience. You&#x27;ll describe the thing, you&#x27;ll share what were your feelings about the thing, you&#x27;ll show the strengths and the weaknesses of the thing. Example of &lt;a href=&quot;https:&#x2F;&#x2F;emptysqua.re&#x2F;blog&#x2F;review-of-autotools-a-practitioners-guide&#x2F;&quot;&gt;review&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h1 id=&quot;identifying-the-target-audience&quot;&gt;&lt;u&gt;Identifying the target audience: &lt;&#x2F;u&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;Identifying your intended audience will help you write effective content that achieves your goals. What are you writing ? Who are you writing for ? Knowing your audience will help you adapt your content accordingly. And if you don&#x27;t know who to write for, then the following is a serie of questions you can ask yourself:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Who am I writing for ?&lt;&#x2F;li&gt;
&lt;li&gt;What subject am I writing about ?&lt;&#x2F;li&gt;
&lt;li&gt;What does my audience already know about the subject?&lt;&#x2F;li&gt;
&lt;li&gt;What does my audience want to know about the subject?&lt;&#x2F;li&gt;
&lt;li&gt;What are the questions will my audience have?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;h1 id=&quot;finding-the-audience&quot;&gt;&lt;u&gt;Finding the audience: &lt;&#x2F;u&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;For example, &lt;strong&gt;as a Python specialist&lt;&#x2F;strong&gt;, the audience can be found in different places. Pycoder weekly news want to hear from you about projects you are working on, conferences you are running, and articles you want to &lt;a href=&quot;https:&#x2F;&#x2F;pycoders.com&#x2F;submissions&quot;&gt;share&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Awesome Python is another newsletter who want you to &lt;a href=&quot;https:&#x2F;&#x2F;python.libhunt.com&#x2F;contribute&quot;&gt;contribute&lt;&#x2F;a&gt; links to blog posts, tutorials, libraries, events, videos, books.&lt;&#x2F;p&gt;
&lt;p&gt;You can als share your posts on &lt;a href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;&quot;&gt;Lobsters&lt;&#x2F;a&gt;, on &lt;a href=&quot;https:&#x2F;&#x2F;tilde.news&#x2F;&quot;&gt;Tilde News&lt;&#x2F;a&gt;, on &lt;a href=&quot;https:&#x2F;&#x2F;dev.to&#x2F;&quot;&gt;dev.to&lt;&#x2F;a&gt;, on &lt;a href=&quot;https:&#x2F;&#x2F;towardsdatascience.com&#x2F;about&quot;&gt;towardsdatascience&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h1 id=&quot;improving-your-writing&quot;&gt;&lt;u&gt;Improving your writing: &lt;&#x2F;u&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;The following is what I recommend. In all the cases, you should find what is best for you.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1-practice&quot;&gt;&lt;em&gt;1. Practice&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The most effective writers write every day, &lt;em&gt;at least a bit&lt;&#x2F;em&gt;.  The more you write, the more your brain form connections between neurons. Those connections get stronger the more often you write. After some time and regular practice, you no longer have to think about it. This is when writing becomes a habit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-make-time&quot;&gt;&lt;em&gt;2. Make time&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Prepare to spend between 90 minutes and 3 hours writing. But hey, 15 minutes can be useful if you do it every day. Don&#x27;t fool yourself, thinking you&#x27;ll wait for a big chunk of free time to start. That will never happen.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3-when&quot;&gt;&lt;em&gt;3. When&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;You are much smarter and more resilient after you have slept properly and ate. Again, find what suits you best. According to some studies, creativity peaks in the morning. My experience tells me that&#x27;s true.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;4-frequency&quot;&gt;&lt;em&gt;4. Frequency&lt;&#x2F;em&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Write only when you feel it.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h1 id=&quot;tools-for-writing-ssg&quot;&gt;&lt;u&gt;Tools for writing... SSG:&lt;&#x2F;u&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;You should provide yourself with the right technology. Here again, I can tell you what I do, but there are plenty of differents tools, you &lt;a href=&quot;https:&#x2F;&#x2F;app.hackernoon.com&#x2F;signup&quot;&gt;should&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;pages.github.com&#x2F;&quot;&gt;always&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;jekyllrb.com&#x2F;&quot;&gt;find&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;substack.com&#x2F;for-bloggers&quot;&gt;what&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;write.as&#x2F;start&quot;&gt;suits&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;www.blogger.com&#x2F;about&#x2F;?bpli=1&quot;&gt;you&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;creators&quot;&gt;best&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve choosen to build my website using a Static Site Generator (SSG). An ssg is a tool that generates a full static HTML website based on raw data (text files) and a set of templates (html, css, js files). :&lt;&#x2F;p&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;ssg2.3f40eef587b8186f.png&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
&lt;p style=&quot;text-align:center&quot;&gt; &lt;a href=&quot;https:&#x2F;&#x2F;devopedia.org&#x2F;static-site-generators&quot;&gt;Image source&lt;&#x2F;a&gt; &lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h1 id=&quot;why-ssg&quot;&gt;&lt;u&gt;Why SSG:&lt;&#x2F;u&gt;&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;No need for internet for writing, no need to login somewhere before writing.&lt;&#x2F;li&gt;
&lt;li&gt;no need for a particular environment, just a text editor, and a browser.&lt;&#x2F;li&gt;
&lt;li&gt;No vendor lock in, no dependency on any product for writing or migrating your content.&lt;&#x2F;li&gt;
&lt;li&gt;No need for a program to dynamically generate webpages. Web pages load faster.&lt;&#x2F;li&gt;
&lt;li&gt;No dependencies running on the server, just a web server. Increased security&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;h1 id=&quot;i-m-convinced-can-you-show-me-an-example-please&quot;&gt;&lt;u&gt;I&#x27;m convinced, can you show me an example please:&lt;&#x2F;u&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;blg&#x2F;&quot;&gt;article&lt;&#x2F;a&gt; you&#x27;re reading right now, was generated from a &lt;a href=&quot;https:&#x2F;&#x2F;bin.nskm.xyz&#x2F;pastes&#x2F;markdown.md&quot;&gt;markdown file&lt;&#x2F;a&gt; using an SSG named &lt;a href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zola&lt;&#x2F;a&gt; and a theme named &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;barlog-m&#x2F;oceanic-zen&quot;&gt;Oceanic Zen&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p&gt;To finish this article, I would like to quote &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Leslie_Lamport&quot;&gt;Leslie Lamport&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&quot;If you’re thinking without writing, you only think you’re thinking.&quot;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;— Leslie Lamport&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;br&gt;
&lt;h1 id=&quot;links&quot;&gt;Links:&lt;&#x2F;h1&gt;
&lt;p&gt;To learn more on this topic, I strongly recommend the following links:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.yieldcode.blog&#x2F;post&#x2F;why-engineers-should-write&#x2F;&quot;&gt;Why engineers should focus on writing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=RnY5iJea5ww&amp;amp;t=77s&quot;&gt;Think and write, with Leslie Lamport&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=HOXwDWCoqQg&quot;&gt;Jordan Peterson on the importance of reading and writing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=vyVpRiqOvt4&quot;&gt;How writing online made me a millionaire&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=tod1sraj8we&quot;&gt;How to improve your clarity of thought (&quot;writing is thinking&quot;)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=fxLFjOa-9UY&quot;&gt;Programmers that don&#x27;t blog should start right now&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=p8dve3MqQW4&quot;&gt;Benefits of writing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=mmU25Xd0BGs&quot;&gt;Technical blogging for Python programmers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=aTgPJQ9Dy7Q&quot;&gt;Look deeper -- write -- the wonders of writing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=t4vKPhjcMZg&quot;&gt;What nobody tells you about documentation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Verba_volant,_scripta_manent&quot;&gt;Spoken words fly away, written words remain&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Circadian_rhythm&quot;&gt;Circadian rythm&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;links-again&quot;&gt;Links again:&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;jamstack.org&#x2F;generators&#x2F;&quot;&gt;Static Site Generators&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;about.gitlab.com&#x2F;blog&#x2F;2022&#x2F;04&#x2F;18&#x2F;comparing-static-site-generators&#x2F;&quot;&gt;How to choose the right static site generator&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zola, your one-stop static site engine&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;getpublii.com&#x2F;&quot;&gt;Publii, Static Site Generator with GUI&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;gohugo.io&#x2F;&quot;&gt;Hugo, the world’s fastest framework for building websites&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;git.disroot.org&#x2F;orbifx&#x2F;logarion&quot;&gt;Logarion, a suite of tools, for discovering, collecting &amp;amp; exchanging texts&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;even-more-links&quot;&gt;Even more links:&lt;&#x2F;h1&gt;
&lt;p&gt;Things that were discussed during the talk:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Literate_programming&quot;&gt;Literate programming&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=Mr3WTR0a5SM&quot;&gt;Knuth on Literate Programming&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;orgmode.org&#x2F;worg&#x2F;org-contrib&#x2F;babel&#x2F;&quot;&gt;Babel: active code in Org-mode&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;pandoc.org&#x2F;&quot;&gt;Pandoc, a universal document converter&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;quarto.org&#x2F;&quot;&gt;Quarto, open-source scientific and technical publishing system built on Pandoc&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;wr2.c2d34d34c2abf8e1.jpg&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Function pointers</title>
        <published>2022-04-29T16:15:50+00:00</published>
        <updated>2022-04-29T16:15:50+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/fp/"/>
        <id>https://nskm.xyz/posts/fp/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/fp/">&lt;p&gt;In Python, we say, functions are &lt;em&gt;first class citizen&lt;&#x2F;em&gt;. This means, functions can be used like any other objects. They can be stored inside variables, they can be passed as argument to a function, they can be returned from a function. The following is a very basic example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;square = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;lambda &lt;&#x2F;span&gt;&lt;span&gt;x: x * x
&lt;&#x2F;span&gt;&lt;span&gt;cube = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;lambda &lt;&#x2F;span&gt;&lt;span&gt;x: x * x * x
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;operations = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;: square, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;: cube}
&lt;&#x2F;span&gt;&lt;span&gt;choice = int(input(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Square (1) or Cube (2) ?: &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;value = int(input(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Value ?: &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;print(operations[choice](value))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;Let&#x27;s start with a very simple function to print out a simple &quot;hello world&quot; using a function pointer:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; defining a function ptr
&lt;&#x2F;span&gt;&lt;span&gt;void (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;greet_ptr)();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; a function taking no argument and returning nothing
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;greet(){
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Hello world!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main(){
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; make our function pointer points to greet function
&lt;&#x2F;span&gt;&lt;span&gt;  greet_ptr = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;greet;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; call greet function via the function pointer
&lt;&#x2F;span&gt;&lt;span&gt;  greet_ptr();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h3 id=&quot;slowly-please&quot;&gt;&lt;strong&gt;Slowly please?&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;The first interesting line is:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span&gt;void (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;greet_ptr)();
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;We&#x27;re defining a &lt;em&gt;pointer to a function&lt;&#x2F;em&gt;, named &lt;strong&gt;greet_ptr&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;We&#x27;re using the &lt;strong&gt;*&lt;&#x2F;strong&gt; notation to signify that it is a pointer.&lt;&#x2F;li&gt;
&lt;li&gt;The function pointed to, should receive no argument: &lt;strong&gt;()&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The function should return nothing: &lt;strong&gt;void&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;We need parenthesis, otherwise it becomes &lt;strong&gt;void *greet_ptr()&lt;&#x2F;strong&gt;, a function returning a &lt;strong&gt;void pointer.&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;br&gt;
&lt;p&gt;The next interesting lines are:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span&gt;greet_ptr = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;greet;
&lt;&#x2F;span&gt;&lt;span&gt;greet_ptr();
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;greet_ptr&lt;&#x2F;code&gt; is a pointer, so it should receive &lt;em&gt;the address&lt;&#x2F;em&gt; of a function.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;greet&lt;&#x2F;code&gt; is a function, taking no argument, and returning void.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;greet_ptr()&lt;&#x2F;code&gt;: let&#x27;s execute the code living at the address stored by greet_ptr.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;br&gt;
&lt;h3 id=&quot;what-if-the-function-pointed-to-takes-arguments&quot;&gt;&lt;strong&gt;What if the function pointed to, takes arguments?&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Simple example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; defining a function ptr
&lt;&#x2F;span&gt;&lt;span&gt;void (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;greet_ptr)(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;greet(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;name){
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Hello &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, name);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main(){
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; make our function pointer points to greet function
&lt;&#x2F;span&gt;&lt;span&gt;  greet_ptr = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;greet;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; call greet function via the function pointer
&lt;&#x2F;span&gt;&lt;span&gt;  greet_ptr(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;The first interesting line is:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span&gt;void (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;greet_ptr)(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;We&#x27;re defining a pointer to a function, named &lt;strong&gt;greet_ptr&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;We&#x27;re using the &lt;strong&gt;*&lt;&#x2F;strong&gt; notation to signify that it is a pointer.&lt;&#x2F;li&gt;
&lt;li&gt;The function pointed to, should take one argument of type char pointer &lt;strong&gt;(char *)&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;The function pointed to, should return nothing: &lt;strong&gt;void&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;We need parenthesis, otherwise it becomes &lt;strong&gt;void *greet_ptr(char *)&lt;&#x2F;strong&gt;, a function taking a string and returning a &lt;strong&gt;void pointer.&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;br&gt;
&lt;p&gt;The next interesting lines are:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span&gt;greet_ptr = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;greet;
&lt;&#x2F;span&gt;&lt;span&gt;greet_ptr(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;greet_ptr still points to greet function.&lt;&#x2F;li&gt;
&lt;li&gt;let&#x27;s execute the code living at the address stored by greet_ptr.&lt;&#x2F;li&gt;
&lt;li&gt;This executable, &lt;code&gt;greet&lt;&#x2F;code&gt; is waiting for a parameter of type &lt;code&gt;char *&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;So the parameter &lt;code&gt;&quot;foo&quot;&lt;&#x2F;code&gt; will be passed to the function &lt;code&gt;greet&lt;&#x2F;code&gt; before execution.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;br&gt;
&lt;h3 id=&quot;what-is-the-address-of-a-function&quot;&gt;&lt;strong&gt;What is the address of a function?&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Before going further, we have to keep one thing in mind. &lt;strong&gt;a function name (label) is the address of the function.&lt;&#x2F;strong&gt; Yes. A &lt;code&gt;function name (label)&lt;&#x2F;code&gt; is converted to a &lt;code&gt;pointer to itself&lt;&#x2F;code&gt;. This means that function names can be assigned to a function pointer without using &lt;code&gt;&amp;amp;&lt;&#x2F;code&gt; to pass an address. Example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;void (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;greet_ptr)(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;void (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;hello_ptr)(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;greet(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;name){
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Hello &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, name);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main(){
&lt;&#x2F;span&gt;&lt;span&gt;  greet_ptr = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;greet;
&lt;&#x2F;span&gt;&lt;span&gt;  hello_ptr = greet; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; notice, there is no &amp;amp;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;(greet_ptr == hello_ptr)
&lt;&#x2F;span&gt;&lt;span&gt;    printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Pointers containing the same address.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  greet_ptr(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  hello_ptr(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h3 id=&quot;function-pointers-as-arguments&quot;&gt;&lt;strong&gt;Function pointers as arguments?&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Remember, a function name (label) is converted to a pointer to itself, so it can be passed whenever we need a function pointer. So, we can write function taking function pointers as arguments. Example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;sayHello(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;name){
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Hello &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, name);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;sayHi(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;name){
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Hey &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, name);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; a function that takes a function and a string as parameters
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;greet(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;fctPtr)(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;name) {
&lt;&#x2F;span&gt;&lt;span&gt;  fctPtr(name);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;greetBar(){
&lt;&#x2F;span&gt;&lt;span&gt;  greet(sayHello, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;bar&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main () {
&lt;&#x2F;span&gt;&lt;span&gt;  greet(sayHello, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  greet(sayHi, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;baz&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  greetBar();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;The first interesting lines are:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;greet(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;fctPtr)(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;name) {
&lt;&#x2F;span&gt;&lt;span&gt;  fctPtr(name);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;We&#x27;re defining a function, named &lt;code&gt;greet&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;code&gt;greet&lt;&#x2F;code&gt;  function takes 2 arguments:
&lt;ol&gt;
&lt;li&gt;a function pointer: &lt;code&gt;void (*fctPtr)(char *)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;a char pointer: &lt;code&gt;char *name&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;The function pointed to, should be called with an argument of type &lt;code&gt;char *&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The function pointed to is then called: &lt;code&gt;fctPtr(name)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;br&gt;
&lt;p&gt;The next interesting line is:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span&gt;greet(sayHello, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;sayHello&lt;&#x2F;code&gt; is a function name (label)
&lt;ol&gt;
&lt;li&gt;that will be converted to a pointer to itself.&lt;&#x2F;li&gt;
&lt;li&gt;then, that pointer will be passed to &lt;code&gt;greet&lt;&#x2F;code&gt; function.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;The function &lt;code&gt;sayHello&lt;&#x2F;code&gt; will be called with &lt;code&gt;&quot;foo&quot;&lt;&#x2F;code&gt; as parameter.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;br&gt;
&lt;h3 id=&quot;we-can-also-use-function-pointers-as-return-values&quot;&gt;&lt;strong&gt;We can also use function pointers as return values.&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;We &lt;em&gt;already&lt;&#x2F;em&gt; know a pointer can be returned from a function. A function pointer, &lt;em&gt;is&lt;&#x2F;em&gt; a &lt;em&gt;pointer&lt;&#x2F;em&gt;, so there is no big deal here.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h3 id=&quot;the-original-python-example-in-c&quot;&gt;&lt;strong&gt;The original Python example in C?&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;square (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;x) {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; x;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;cube (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;x) {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; x;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main () {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; choice, value;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; an array of pointers to functions
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; those functions should take an int and return an int
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;fp[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;])(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;) = {square, cube};
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Square (1) or Cube (2) ?: &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  scanf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;choice);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Value ?: &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  scanf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;value);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;fp[choice-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;])(value));
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h3 id=&quot;any-real-life-examples&quot;&gt;&lt;strong&gt;Any real life examples?&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Function pointers gives C programmers, &lt;strong&gt;first-class citizen&lt;&#x2F;strong&gt;  &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;First-class_function&quot;&gt;functionality&lt;&#x2F;a&gt;: being able to pass functions as argument to other functions, and being able to return functions as value from other functions.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h3 id=&quot;more-on-the-topic&quot;&gt;&lt;strong&gt;More on the topic:&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;10758811&#x2F;c-syntax-for-functions-returning-function-pointers&#x2F;10759352#10759352&quot;&gt;C syntax for functions returning function pointers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>My journey to type checking 7521 lines of Python</title>
        <published>2021-11-08T03:40:17+00:00</published>
        <updated>2021-11-08T03:40:17+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/stcmp2/"/>
        <id>https://nskm.xyz/posts/stcmp2/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/stcmp2/">&lt;p&gt;I&#x27;ve spent the last couple of months adding &lt;a href=&quot;http:&#x2F;&#x2F;mypy-lang.org&#x2F;&quot;&gt;type hints&lt;&#x2F;a&gt; to the &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;RQL&#x2F;-&#x2F;merge_requests?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;author_username=nsukami&quot;&gt;RQL package&lt;&#x2F;a&gt;. In the &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;stcmp&#x2F;&quot;&gt;first&lt;&#x2F;a&gt; part, I talked you &lt;strong&gt;the reasons&lt;&#x2F;strong&gt; I think Mypy may be useful. In this part, I&#x27;ll talk about the &lt;strong&gt;process I&#x27;ve followed&lt;&#x2F;strong&gt; for adding type annotations to RQL.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;recap-of-the-first-part&quot;&gt;Recap of the first part:&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Type hints are mainly useful for the &lt;a href=&quot;https:&#x2F;&#x2F;hynek.me&#x2F;talks&#x2F;python-foss&#x2F;&quot;&gt;maintainers&lt;&#x2F;a&gt;, &lt;strong&gt;&lt;em&gt;the human readers&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; of &lt;strong&gt;&lt;em&gt;large code bases&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt;. The  people who &lt;strong&gt;read&lt;&#x2F;strong&gt; and &lt;strong&gt;debug&lt;&#x2F;strong&gt; and &lt;strong&gt;maintain&lt;&#x2F;strong&gt; large software systems &lt;strong&gt;they did not write&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The major benefit for you won&#x27;t be fewer bugs or unit tests, but the ability to more easily read and reason about code written by someone else.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;br&gt;
&lt;h2 id=&quot;outline&quot;&gt;Outline:&lt;&#x2F;h2&gt;
&lt;p&gt;First, I&#x27;ll talk about what &lt;a href=&quot;&#x2F;posts&#x2F;stcmp2&#x2F;#mypy&quot;&gt;Mypy&lt;&#x2F;a&gt; is and what should be it&#x27;s initial &lt;a href=&quot;&#x2F;posts&#x2F;stcmp2&#x2F;#initial-setup&quot;&gt;setup&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Secondly, I&#x27;ll briefly show you how I deconstructed the project (&lt;a href=&quot;&#x2F;posts&#x2F;stcmp2&#x2F;#import-structure&quot;&gt;import structure&lt;&#x2F;a&gt; &amp;amp; &lt;a href=&quot;&#x2F;posts&#x2F;stcmp2&#x2F;#classes-hierarchy&quot;&gt;classes hierarchy&lt;&#x2F;a&gt;) to have another perspective of how the project is built.&lt;&#x2F;p&gt;
&lt;p&gt;I will also show 3 different ways to &lt;a href=&quot;&#x2F;posts&#x2F;stcmp2&#x2F;#type-hints-generation&quot;&gt;generate&lt;&#x2F;a&gt; type annotations and &lt;a href=&quot;&#x2F;posts&#x2F;stcmp2&#x2F;#type-information-inline-or-via-stubs&quot;&gt;where&lt;&#x2F;a&gt; I think those type annotations should reside.&lt;&#x2F;p&gt;
&lt;p&gt;Finaly, I&#x27;ll talk about things that still need to be &lt;a href=&quot;&#x2F;posts&#x2F;stcmp2&#x2F;#improvements&quot;&gt;improved&lt;&#x2F;a&gt;. Mainly, the use of &lt;code&gt;Any&lt;&#x2F;code&gt; and &lt;code&gt;type:ignore&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Feel free to jump straight to the part that&#x27;s most interesting.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;mypy&quot;&gt;Mypy:&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;existing_code.html#using-mypy-with-an-existing-codebase&quot;&gt;Mypy&lt;&#x2F;a&gt; is a library that provides optional static type checking. Unlike other programming languages, where the static type-checking takes place at compilation time, Mypy CLI does the type-check on-demand. At Logilab, the type-check was done, locally when developing, but also in the Continuous Integration pipeline, using Gitlab and Tox.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;initial-setup&quot;&gt;Initial setup:&lt;&#x2F;h2&gt;
&lt;p&gt;We need to ensure that Mypy is really being run everywhere it should be and everytime someone pushes code. We don&#x27;t want to spend time applying type annotations that won&#x27;t be checked. If you don&#x27;t check type annotations on a regular basis, they may become wrong after a certain period of time. That means:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-configuring-mypy&quot;&gt;1. Configuring Mypy&lt;&#x2F;h3&gt;
&lt;p&gt;Configuration is done using a &lt;code&gt;mypy.ini&lt;&#x2F;code&gt; &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;RQL&#x2F;-&#x2F;blob&#x2F;532de9f4788887a4c5ff315ad9a515033979c822&#x2F;mypy.ini&quot;&gt;file&lt;&#x2F;a&gt;. At the begining, we do not want strict typing checks. Then, we&#x27;ll try to work towards more strigency, for example: &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#disallow-dynamic-typing&quot;&gt;dissallowing dynamic typing&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#untyped-definitions-and-calls&quot;&gt;disallowing untyped definitions&lt;&#x2F;a&gt;. We&#x27;re working with a legacy code base with no type definitions, let&#x27;s start with more relaxed options.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-ignoring-external-libraries&quot;&gt;2. Ignoring external libraries:&lt;&#x2F;h3&gt;
&lt;p&gt;I&#x27;ve done it many weeks later, but I could have done it right from the beginning: tell Mypy to &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;RQL&#x2F;-&#x2F;commit&#x2F;66c3196a4d2925183b6f6c943f6368943c3e4522&quot;&gt;ignore&lt;&#x2F;a&gt; missing type hints from &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;running_mypy.html#missing-type-hints-for-third-party-library&quot;&gt;external libraries&lt;&#x2F;a&gt;. Maybe in another phase, we&#x27;ll annotate them, but for now, they should be ignored.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-set-a-tox-environment-and-ci-job&quot;&gt;3. Set a Tox environment and CI job:&lt;&#x2F;h3&gt;
&lt;p&gt;Add Tox environment to automate the boring stuff and reduce the &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;RQL&#x2F;-&#x2F;blob&#x2F;branch&#x2F;default&#x2F;tox.ini#L44&quot;&gt;boilerplate&lt;&#x2F;a&gt;. And add a Gitlab CI &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;RQL&#x2F;-&#x2F;blob&#x2F;branch&#x2F;default&#x2F;.gitlab-ci.yml#L39&quot;&gt;job&lt;&#x2F;a&gt;. that will be in charge of running Mypy every time a new changeset is sent to the Gitlab server.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;import-structure&quot;&gt;Import structure&lt;&#x2F;h2&gt;
&lt;p&gt;I thought a diagram showing the import structure would help me understand the project. I also thought making a graph of the RQL&#x27;s import structure would help me add types a bit faster. My idea was to add annotations from bottom to top. I was wrong. More than once, after adding type annotations to a module, I was obliged to go back to where it was already done. For example, method &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;common_issues.html#incompatible-overrides&quot;&gt;overrides&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thebjorn&#x2F;pydeps&quot;&gt;PyDeps&lt;&#x2F;a&gt; is the module dependency visualization I used, the result being:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;import_structure2.svg&quot; alt=&quot;&quot; title=&quot;Right click &amp;amp; Open in new tab for better view&quot; &#x2F;&gt;
&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If you open the diagram in another tab, you&#x27;ll notice that we can see external libraries too, for example: &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;open-source&#x2F;logilab-database&quot;&gt;logilab-database&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;smurfix&#x2F;yapps&quot;&gt;yapps&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pygments&#x2F;pygments&quot;&gt;pygments&lt;&#x2F;a&gt;. Those are the ones that need to be ignored during type checking.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;classes-hierachy&quot;&gt;Classes hierachy:&lt;&#x2F;h2&gt;
&lt;p&gt;Within &lt;a href=&quot;https:&#x2F;&#x2F;pylint.org&#x2F;&quot;&gt;Pylint&lt;&#x2F;a&gt;, there is a tool named &lt;a href=&quot;https:&#x2F;&#x2F;www.logilab.org&#x2F;blogentry&#x2F;6883&quot;&gt;Pyreverse&lt;&#x2F;a&gt; that analyses Python code and extracts UML class diagrams and package dependencies. Using Pyreverse, we can have a clear view of all the classes and the relation between them:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;classes_RQL2.svg&quot; alt=&quot;&quot; title=&quot;Right click &amp;amp; Open in new tab for better view&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;type-hints-addition&quot;&gt;Type hints addition:&lt;&#x2F;h2&gt;
&lt;p&gt;There are different options for adding type annotations.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-manual&quot;&gt;1. Manual&lt;&#x2F;h3&gt;
&lt;p&gt;We can do it manually: finding what are the types flowing through our program, &lt;em&gt;I&#x27;ve been there, it&#x27;s painful&lt;&#x2F;em&gt;. Literally:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Adding breakpoints here and there&lt;&#x2F;li&gt;
&lt;li&gt;Running the function or running the tests&lt;&#x2F;li&gt;
&lt;li&gt;Once inside PDB, asking the &lt;code&gt;type&lt;&#x2F;code&gt; function to tell me who is who&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;  
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;73&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;g(x):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     breakpoint()
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;foo&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     y = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;42
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# a long list of non understandable code
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;y
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;76&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# let&amp;#39;s assume we launched the tests and somewhere, g is called
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;77&lt;&#x2F;span&gt;&lt;span&gt;]: g([&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;72&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;38&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;45&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;21&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;34&lt;&#x2F;span&gt;&lt;span&gt;])
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; &amp;lt;ipython-input-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;75&lt;&#x2F;span&gt;&lt;span&gt;-ef8444a3ab59&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;)g()
&lt;&#x2F;span&gt;&lt;span&gt;-&amp;gt; x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;foo&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;(Pdb) type(x)  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# please, what is the type of the parameter x?
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;list&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;(Pdb) n
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; &amp;lt;ipython-input-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;75&lt;&#x2F;span&gt;&lt;span&gt;-ef8444a3ab59&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;)g()
&lt;&#x2F;span&gt;&lt;span&gt;-&amp;gt; y = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;42
&lt;&#x2F;span&gt;&lt;span&gt;(Pdb) n
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; &amp;lt;ipython-input-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;75&lt;&#x2F;span&gt;&lt;span&gt;-ef8444a3ab59&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;)g()
&lt;&#x2F;span&gt;&lt;span&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;y
&lt;&#x2F;span&gt;&lt;span&gt;(Pdb) type(y) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# please, what is the type of the returned value?
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;int&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;(Pdb)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;After that first run, we may be temped to write our function like one that takes a list and returns an integer:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;80&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# g takes a list and return an integer
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;In [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;81&lt;&#x2F;span&gt;&lt;span&gt;]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff3333;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;g(x: list) -&amp;gt; int:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;foo&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     y = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;42
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# a long list of non understandable code
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;:     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;y
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;: 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;I said &lt;em&gt;&quot;temped&quot;&lt;&#x2F;em&gt; because, maybe the function takes a dictionary and returns an integer. Only an extensive set of tests will tell us what&#x27;s the best answer.&lt;br &#x2F;&gt;
&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-reveal&quot;&gt;2. Reveal:&lt;&#x2F;h3&gt;
&lt;p&gt;I never really use them, but another option is to use &lt;code&gt;reveal_type&lt;&#x2F;code&gt; or &lt;code&gt;reveal_locals&lt;&#x2F;code&gt;  &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;latest&#x2F;common_issues.html#displaying-the-type-of-an-expression&quot;&gt;functions&lt;&#x2F;a&gt;. You just put a &lt;code&gt;reveal_type(expr)&lt;&#x2F;code&gt; in the code, and run it with Mypy. I never really use those 2 functions because most of the time, the revealed type is &lt;code&gt;Any&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;reveal.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;br &#x2F;&gt;
&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-pyannotate&quot;&gt;3. PyAnnotate:&lt;&#x2F;h3&gt;
&lt;p&gt;The third &lt;em&gt;and really helpful&lt;&#x2F;em&gt; option I want to suggest is, using a tool that will give you an &lt;strong&gt;exhaustive list of suggestions&lt;&#x2F;strong&gt;, for example PyAnnotate. &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dropbox&#x2F;pyannotate&quot;&gt;PyAnnotate&lt;&#x2F;a&gt; will help you list all the &lt;strong&gt;call arguments and all the return types observed at runtime&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Similar projects exists, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Instagram&#x2F;MonkeyType&quot;&gt;MonkeyType&lt;&#x2F;a&gt; created by Instagram. &lt;a href=&quot;https:&#x2F;&#x2F;google.github.io&#x2F;pytype&#x2F;&quot;&gt;Pytype&lt;&#x2F;a&gt; from Google. And &lt;a href=&quot;https:&#x2F;&#x2F;pyre-check.org&#x2F;&quot;&gt;Pyre&lt;&#x2F;a&gt; created at Facebook... &lt;em&gt;Hem, I mean, Meta&lt;&#x2F;em&gt;. I&#x27;ve used PyAnnotate just because it felt like the most easiest to setup and to use. I should probably give a try to the other options.&lt;&#x2F;p&gt;
&lt;p&gt;In the repository, there is a configuration  &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dropbox&#x2F;pyannotate&#x2F;blob&#x2F;master&#x2F;example&#x2F;example_conftest.py&quot;&gt;example&lt;&#x2F;a&gt; you can use with Pytest. And after running your tests, you should find a new file named &lt;code&gt;type_info.json&lt;&#x2F;code&gt;. This file will contain a json that looks like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;path&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;rql&#x2F;__init__.py&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;line&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;128&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;func_name&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;RQLHelper.compute_solutions&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;type_comments&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;(rql.stmts.Union, None, None, int) -&amp;gt; Set&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;(rql.stmts.Insert, None, None, int) -&amp;gt; Set&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;(rql.stmts.Union, Dict[str, function], None, int) -&amp;gt; Set&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;(rql.stmts.Delete, None, None, int) -&amp;gt; Set&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;(rql.stmts.Set, None, None, int) -&amp;gt; Set&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;(rql.stmts.Union, Dict[str, function], Dict[str, str], int) -&amp;gt; Set[str]&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;(rql.stmts.Union, None, None, int) -&amp;gt; pyannotate_runtime.collect_types.NoReturnType&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;(rql.stmts.Insert, None, None, int) -&amp;gt; pyannotate_runtime.collect_types.NoReturnType&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        ],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;samples&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;65
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;path&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;rql&#x2F;__init__.py&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;line&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;152&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;func_name&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;RQLHelper.simplify&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;type_comments&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;(rql.stmts.Union) -&amp;gt; None&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        ],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;samples&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;14
&lt;&#x2F;span&gt;&lt;span&gt;    },    
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Those generated type-hints are &lt;strong&gt;suggestions&lt;&#x2F;strong&gt;. You will have to tweak them first, then apply them. Once applied, you should run mypy on the updated files to verify that everything stays green.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;how-much-should-be-typed&quot;&gt;How much should be typed?&lt;&#x2F;h2&gt;
&lt;p&gt;I won&#x27;t deny, I was &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;existing_code.html#using-mypy-with-an-existing-codebase&quot;&gt;gradually&lt;&#x2F;a&gt; adding annotation to everything, everywhere. There was a feeling of endlessness.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;everywhere.gif&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Then I asked myself: &lt;em&gt;&quot;How do I know the RQL package has enough annotations? How do I know that I&#x27;ve done enough?&quot;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I decided to &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;RQL&#x2F;-&#x2F;commit&#x2F;68f034d32bb10d8ce8c7244c361afe219cc0cca8&quot;&gt;follow&lt;&#x2F;a&gt; a path: adding Mypy &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;command_line.html#cmdoption-mypy-txt-report&quot;&gt;coverage reports&lt;&#x2F;a&gt; to the project. The lower the percentage, the happier you should be:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;Mypy Type Check Coverage Summary
&lt;&#x2F;span&gt;&lt;span&gt;================================
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Script: index
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;+---------------------+-------------------+----------+
&lt;&#x2F;span&gt;&lt;span&gt;| Module              | Imprecision       | Lines    |
&lt;&#x2F;span&gt;&lt;span&gt;+---------------------+-------------------+----------+
&lt;&#x2F;span&gt;&lt;span&gt;| rql                 |  29.63% imprecise |  324 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql._exceptions     |   0.00% imprecise |   48 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql.analyze         |  62.35% imprecise |  603 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql.base            |  13.19% imprecise |  288 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql.interfaces      |  11.54% imprecise |   78 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql.nodes           |  24.20% imprecise | 1438 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql.parser          |  77.19% imprecise | 1245 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql.parser.__main__ |  19.30% imprecise |   57 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql.pygments_ext    |  23.21% imprecise |   56 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql.rqlgen          |   1.62% imprecise |  247 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql.rqltypes        |  12.92% imprecise |  178 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql.stcheck         |  49.25% imprecise |  867 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql.stmts           |  30.98% imprecise | 1372 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql.undo            |  27.39% imprecise |  387 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;| rql.utils           |  20.72% imprecise |  333 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;+---------------------+-------------------+----------+
&lt;&#x2F;span&gt;&lt;span&gt;| Total               |  38.64% imprecise | 7521 LOC |
&lt;&#x2F;span&gt;&lt;span&gt;+---------------------+-------------------+----------+
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;Mypy does &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;type_inference_and_annotations.html#type-inference&quot;&gt;type inference&lt;&#x2F;a&gt;, it can guess the types of values based on the context. We see in the picture below that even though there is no type annotations, the program is not flagged as 100% imprecise:
&lt;img src=&quot;&#x2F;images&#x2F;mypy_reports_one.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;br &#x2F;&gt;
&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I finally &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;RQL&#x2F;-&#x2F;commit&#x2F;00efe84a7e18f71cf4741dbd71736b6549dfbd0b&quot;&gt;gave up&lt;&#x2F;a&gt;, to focus on what other &lt;em&gt;Logilabians&lt;&#x2F;em&gt;, suggested: &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;cubicweb&#x2F;-&#x2F;snippets&#x2F;61#LC41&quot;&gt;find&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;cubicweb&#x2F;-&#x2F;issues&#x2F;218&quot;&gt;list&lt;&#x2F;a&gt; what are the &lt;strong&gt;RQL&#x27;s most imported&#x2F;used classes and functions&lt;&#x2F;strong&gt;. If those classes and functions are typed, we&#x27;ll consider we&#x27;ve reach a milestone.&lt;br &#x2F;&gt;
&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;type-information-inline-or-via-stubs&quot;&gt;Type information inline or via stubs?&lt;&#x2F;h2&gt;
&lt;p&gt;Mypy gives you the ability to add type annotations to your project without ever modifying the original source code. You do it using what&#x27;s called &quot;stub files&quot;. &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;stubs.html&quot;&gt;Stub&lt;&#x2F;a&gt; files are python-like files, that only contain type-checked variable, function, and class definitions. Nothing else.&lt;&#x2F;p&gt;
&lt;p&gt;I went the other way, I&#x27;ve added type annotations directly within the original source code. In the beginning, it really felt like the easiest thing to do, having everything in the same file. But now that there is more and more types, I think I&#x27;m better improve readability.&lt;&#x2F;p&gt;
&lt;p&gt;I can for example write &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;kinds_of_types.html#type-aliases&quot;&gt;type aliases&lt;&#x2F;a&gt; whenever &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;RQL&#x2F;-&#x2F;blob&#x2F;branch&#x2F;default&#x2F;rql&#x2F;stcheck.py#L158&quot;&gt;necessary&lt;&#x2F;a&gt;. Interesting inspiration can be found &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dropbox&#x2F;incubator-superset-internal&#x2F;blob&#x2F;4cf3f99ee881a10995212828494f0b126dd5415e&#x2F;superset&#x2F;typing.py&quot;&gt;here&lt;&#x2F;a&gt;. I can also write a snippet that will strip all those annotations and put them inside &lt;code&gt;.pyi&lt;&#x2F;code&gt; files.&lt;&#x2F;p&gt;
&lt;p&gt;From now on, I think I&#x27;ll always use stub files.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;type-checking&quot;&gt;Type Checking:&lt;&#x2F;h2&gt;
&lt;p&gt;The typing module defines a &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html#typing.TYPE_CHECKING&quot;&gt;TYPE_CHECKING&lt;&#x2F;a&gt; constant that is &lt;code&gt;False&lt;&#x2F;code&gt; at runtime but treated as &lt;code&gt;True&lt;&#x2F;code&gt; while type checking. This technique is used to tell mypy something without the code being evaluated at runtime, for example resolving import cycles. Example &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;RQL&#x2F;-&#x2F;blob&#x2F;branch&#x2F;default&#x2F;rql&#x2F;nodes.py#L51&quot;&gt;here&lt;&#x2F;a&gt;, another one &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;RQL&#x2F;-&#x2F;blob&#x2F;branch&#x2F;default&#x2F;rql&#x2F;stmts.py#L243&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;improvements&quot;&gt;Improvements:&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1-less-any&quot;&gt;&lt;em&gt;1. Less Any:&lt;&#x2F;em&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;I&#x27;ve been into situations where I&#x27;m not sure what should be the correct type annotation. Instead of leaving an empty type annotation, I put &lt;code&gt;Any&lt;&#x2F;code&gt;, to show other developers that the lack of a restrictive type hint is a conscious choice: either I don&#x27;t know, either I&#x27;m not sure.&lt;&#x2F;p&gt;
&lt;p&gt;Normally, I should use &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html#the-any-type&quot;&gt;Any&lt;&#x2F;a&gt; only if it&#x27;s impossible for me to know what the type is going to be.&lt;&#x2F;p&gt;
&lt;p&gt;From the documentation we can &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html#the-any-type&quot;&gt;read&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Notice that no type checking is performed when assigning a value of type Any to a more precise type. For example, the static type checker did not report an error when assigning a to s even though s was declared to be of type str and receives an int value at runtime!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;So, to take advantage of Mypy, I should really avoid using &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;search?group_id=23&amp;amp;nav_source=navbar&amp;amp;page=1&amp;amp;project_id=300&amp;amp;repository_ref=branch%2Fdefault&amp;amp;scope=&amp;amp;search=%3A+Any&amp;amp;search_code=true&amp;amp;snippets=false&quot;&gt;Any&lt;&#x2F;a&gt; and see if I can replace it with a proper annotation.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-less-type-ignore-comments&quot;&gt;&lt;em&gt;2. Less type: ignore comments:&lt;&#x2F;em&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;It was also impossible to progress without using &lt;code&gt;# type: ignore&lt;&#x2F;code&gt; comments, to work around the trickier cases. There are still too many &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;search?group_id=23&amp;amp;nav_source=navbar&amp;amp;page=1&amp;amp;project_id=300&amp;amp;search=%3A+ignore&quot;&gt;type: ignore&lt;&#x2F;a&gt; comments. I should have another look and see if I can improve the type annotations and remove some of those type: ignore comments.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;thanks&quot;&gt;Thanks:&lt;&#x2F;h2&gt;
&lt;p&gt;Special thanks to &lt;a href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;romaricst&quot;&gt;Romaric&lt;&#x2F;a&gt; who took the time to read this article and provide insightful critiques.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;more-on-this-topic&quot;&gt;More on this topic:&lt;&#x2F;h2&gt;
&lt;p&gt;Really hope you&#x27;ve learned something reading this article. As always, the topic is wide and cannot be completely covered here. To discover more about this subject, I strongly recommend the following links:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;typeddjango&#x2F;awesome-python-typing&quot;&gt;Awesome typing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=8wjntHrTGPs&quot;&gt;Liskov Substitution Principle with Johan Vergeer&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;dropbox.tech&#x2F;application&#x2F;our-journey-to-type-checking-4-million-lines-of-python&quot;&gt;Our journey to type checking 4 million lines of Python&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;instagram-engineering.com&#x2F;static-analysis-at-scale-an-instagram-story-8f498ab71a0c&quot;&gt;Static analysis at scale: an Instagram story&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>To type or not to type? That is the question</title>
        <published>2021-08-22T03:40:17+00:00</published>
        <updated>2021-08-22T03:40:17+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/stcmp/"/>
        <id>https://nskm.xyz/posts/stcmp/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/stcmp/">&lt;p&gt;I&#x27;ve spent the last couple of months adding &lt;a href=&quot;http:&#x2F;&#x2F;mypy-lang.org&#x2F;&quot;&gt;type hints&lt;&#x2F;a&gt; to the &lt;a href=&quot;https:&#x2F;&#x2F;forge.extranet.logilab.fr&#x2F;cubicweb&#x2F;RQL&#x2F;-&#x2F;merge_requests?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;author_username=nsukami&quot;&gt;RQL package&lt;&#x2F;a&gt;. In this first part, I&#x27;ll try to tell you &lt;strong&gt;when&lt;&#x2F;strong&gt; I think Mypy may be useful. In a &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;stcmp2&#x2F;&quot;&gt;second part&lt;&#x2F;a&gt;, I&#x27;ll talk about the &lt;strong&gt;how&lt;&#x2F;strong&gt;, the process I&#x27;ve followed for adding type annotations to RQL. In a last part, I&#x27;ll talk about what I&#x27;ve &lt;strong&gt;learned&lt;&#x2F;strong&gt; during the process.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;what&quot;&gt;What?&lt;&#x2F;h2&gt;
&lt;p&gt;Yes, in case you were living under a rock, here are the news: you can now write Python &lt;strong&gt;as if&lt;&#x2F;strong&gt; it was a static programming language. The official &lt;a href=&quot;https:&#x2F;&#x2F;www.python.org&#x2F;dev&#x2F;peps&#x2F;pep-0484&#x2F;&quot;&gt;PEP&lt;&#x2F;a&gt;, the official &lt;a href=&quot;http:&#x2F;&#x2F;www.mypy-lang.org&#x2F;&quot;&gt;website&lt;&#x2F;a&gt;. The official &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;&quot;&gt;documentation&lt;&#x2F;a&gt;. And the official &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;python&#x2F;mypy&quot;&gt;repository&lt;&#x2F;a&gt; &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#4&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. The &lt;a href=&quot;http:&#x2F;&#x2F;www.alorelang.org&#x2F;&quot;&gt;Alore&lt;&#x2F;a&gt; programming language, the project Mypy borrows heavily from.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;why&quot;&gt;Why?&lt;&#x2F;h2&gt;
&lt;p&gt;I remember when I was asked to work on this task. The (my) skepticism was real. Around me, reactions were mixed (confused, disgusted, interesed). I won&#x27;t deny, sometimes, I&#x27;m really wondering if I&#x27;m not better go and learn to write &lt;a href=&quot;https:&#x2F;&#x2F;ocaml.org&#x2F;learn&#x2F;&quot;&gt;OCaml&lt;&#x2F;a&gt;. Python devs are so used to quickly prototype their programs, without worrying about the types of their variables, without worrying about their return types, etc. You cannot just come and tell them that type hints are nice! They need to be convinced.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;what.gif&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;More than once, the discussion ended with the &quot;explicit vs implicit&quot;, &quot;static vs dynamic&quot; holy wars, etc... I&#x27;m not trying to fuel those debates. There are pros and cons on each sides. You have to know what are the tools, what suits you best, depending on what you&#x27;re trying to achieve, depending on what is your position (user, author, maintainer).&lt;&#x2F;p&gt;
&lt;p&gt;Assuming you&#x27;re a person who already write Python programs, and you want to discover more about Mypy. If you only look at some introductory examples, they will help you understand &lt;strong&gt;what&#x27;s going on.&lt;&#x2F;strong&gt; They won&#x27;t &lt;strong&gt;convince&lt;&#x2F;strong&gt; you to jump on the type-hints band wagon. The problem with most of the examples is, they&#x27;re too short, or too basic.&lt;&#x2F;p&gt;
&lt;p&gt;No disrepect to the authors, I guess, the intent was to make things easier to understand. Short and simple to get to the point. But short and simple would barely convince you to try.&lt;&#x2F;p&gt;
&lt;p&gt;So, what are the situations in which adding types to your program will be useful, necessary, not a waste of time, priceless, meaningful? To this question, I would say this:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Type hints are mainly useful for the &lt;a href=&quot;https:&#x2F;&#x2F;hynek.me&#x2F;talks&#x2F;python-foss&#x2F;&quot;&gt;maintainers&lt;&#x2F;a&gt;, &lt;strong&gt;&lt;em&gt;the human readers&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; of &lt;strong&gt;&lt;em&gt;large code bases&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt;. The  people who &lt;strong&gt;read&lt;&#x2F;strong&gt; and &lt;strong&gt;debug&lt;&#x2F;strong&gt; and &lt;strong&gt;maintain&lt;&#x2F;strong&gt; large software systems &lt;strong&gt;they did not write&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The major benefit for you won&#x27;t be fewer bugs or unit tests, but the ability to more easily read and reason about code written by someone else.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;br&gt;
&lt;h2 id=&quot;i-need-to-know-the-types&quot;&gt;I need to know the types:&lt;&#x2F;h2&gt;
&lt;p&gt;When you read&#x2F;debug&#x2F;maintain a large software system you&#x27;ve not written, you&#x27;ll often be in the position in which you ask yourself: &quot;Those function arguments, those variables, what are their types?&quot;, or &quot;Is this function returning something?&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Remember, you were reading the source code, now you need to: modifiy the source code, add a couple of: &lt;code&gt;print(foo)&lt;&#x2F;code&gt;, &lt;code&gt;type(bar)&lt;&#x2F;code&gt;, &lt;code&gt;isinstance(baz)&lt;&#x2F;code&gt;, &lt;code&gt;qux.__class__&lt;&#x2F;code&gt;, &lt;code&gt;corge.__dict__&lt;&#x2F;code&gt;. You will probably add &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;functions.html#breakpoint&quot;&gt;breakpoints&lt;&#x2F;a&gt; here and there, to dive inside &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;pdb.html&quot;&gt;pdb&lt;&#x2F;a&gt;. Then start a REPL, then launch the program, then do some instrospection, then see what&#x27;s going on. And finally, discover that the type is not what you were expecting.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;c.tenor.com&#x2F;vZrArZhxAUoAAAAd&#x2F;hugh-laurie-facepalm.gif&quot; alt=&quot;phew&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;what-about-just-reading-the-type&quot;&gt;What about just reading the type?&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s be honest, as a &lt;em&gt;reader&lt;&#x2F;em&gt;, as the one who review millions of lines of code, you just want to be able to &lt;em&gt;read&lt;&#x2F;em&gt; what are the types. And I&#x27;m not talking about &lt;a href=&quot;https:&#x2F;&#x2F;www.python.org&#x2F;dev&#x2F;peps&#x2F;pep-0257&#x2F;&quot;&gt;docstrings&lt;&#x2F;a&gt;. Everybody should document their programs and write docstrings. But let&#x27;s face it, docstrings may be missing, misleading, out of date, not clear enough, etc.... Let&#x27;s compare the 2 following &lt;em&gt;shorts&lt;&#x2F;em&gt; snippets:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;get_description(self, tr): &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# What is tr ???
&lt;&#x2F;span&gt;&lt;span&gt;        foo = self.get_foo()
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;foo != &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Bar&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;tr(foo) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# ah, tr is a function. What&amp;#39;s returned by tr?
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Bar&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# The method seems to return a string
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Imagine having to find answers to those questions many times in a day?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;get_description(self, tr: rt.TranslationFunction) -&amp;gt; Optional[str]:
&lt;&#x2F;span&gt;&lt;span&gt;        foo = self.get_foo()
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;foo != &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Bar&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;tr(foo)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Bar&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You see that in the second snippet, all the important informations are on the function header. You don&#x27;t even read the function body and you already know that: &lt;strong&gt;&quot;get_description is a method that takes a function as its only parameter and return a string or nothing&quot;&lt;&#x2F;strong&gt;. That&#x27;s a game changer when you&#x27;re a maintainer.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s not a surprise, &lt;a href=&quot;https:&#x2F;&#x2F;google.github.io&#x2F;pytype&#x2F;&quot;&gt;all&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;pyre-check.org&#x2F;&quot;&gt;the&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Microsoft&#x2F;pyright&quot;&gt;big&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;monkeytype.readthedocs.io&#x2F;en&#x2F;latest&#x2F;&quot;&gt;companies&lt;&#x2F;a&gt;, the ones with large software systems, are already using type annotations.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;too-verbose-and-confusing-to-read&quot;&gt;Too verbose and confusing to read?&lt;&#x2F;h2&gt;
&lt;p&gt;Adding type annotation can quickly lead to a source code that is too verbose and disgusting to read. The following is something I&#x27;ve written for RQL. I think I can do better (define type aliases, use stub files, use dataclasses, refactor, ...)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;ScopeNode(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;BaseNode&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;__init__(self):
&lt;&#x2F;span&gt;&lt;span&gt;        self.defined_vars: Dict[str, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;rql.nodes.Variable&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;] = {}
&lt;&#x2F;span&gt;&lt;span&gt;        self.with_: List[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;rql.nodes.SubQuery&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;] = []
&lt;&#x2F;span&gt;&lt;span&gt;        self.solutions: rt.SolutionsList = []
&lt;&#x2F;span&gt;&lt;span&gt;        self._varmaker = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None
&lt;&#x2F;span&gt;&lt;span&gt;        self.where: Optional[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;rql.base.Node&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None
&lt;&#x2F;span&gt;&lt;span&gt;        self.having: Iterable[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;rql.base.Node&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;] = ()
&lt;&#x2F;span&gt;&lt;span&gt;        self.schema: Optional[Any] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None
&lt;&#x2F;span&gt;&lt;span&gt;        self.aliases: Dict[str, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;rql.nodes.ColumnAlias&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;] = {}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h2 id=&quot;stub-files&quot;&gt;Stub files?&lt;&#x2F;h2&gt;
&lt;p&gt;If you want to keep your source code free of type annotations, but still want to use type annotations, you can write &lt;a href=&quot;https:&#x2F;&#x2F;www.python.org&#x2F;dev&#x2F;peps&#x2F;pep-0484&#x2F;#stub-files&quot;&gt;stub files&lt;&#x2F;a&gt;. A stub file is just a file that will contain all your variables, function signatures, &lt;em&gt;annotated&lt;&#x2F;em&gt;. &lt;strong&gt;Function bodies in stub files are just a single ellipsis.&lt;&#x2F;strong&gt; Another really short example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# foo.py
&lt;&#x2F;span&gt;&lt;span&gt;    
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;get_description(self, tr):
&lt;&#x2F;span&gt;&lt;span&gt;        foo = self.get_foo()
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;foo != &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Bar&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;tr(foo)
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Bar&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# foo.pyi &amp;lt;--- notice the extension used for stub files
&lt;&#x2F;span&gt;&lt;span&gt;    
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;get_description(self, tr: rt.TranslationFunction) -&amp;gt; Optional[str]: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h2 id=&quot;i-want-type-annotations-what-s-next&quot;&gt;I want type annotations, what&#x27;s next?&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;introduction.html#introduction&quot;&gt;Mypy&lt;&#x2F;a&gt; is a static type checker for Python. Let&#x27;s see what Mypy can to for us.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h3 id=&quot;1-generating-type-annotations&quot;&gt;1. Generating type annotations:&lt;&#x2F;h3&gt;
&lt;p&gt;Let&#x27;s suppose you want to add type annotations to your code base. How do you proceed?&lt;&#x2F;p&gt;
&lt;p&gt;Mypy includes the &lt;a href=&quot;https:&#x2F;&#x2F;mypy.readthedocs.io&#x2F;en&#x2F;stable&#x2F;stubgen.html&quot;&gt;stubgen&lt;&#x2F;a&gt; tool that can automatically generate stub files. For example, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;LeMeteore&#x2F;typeshed&#x2F;blob&#x2F;b2e1083560e223ec415fcb4dd155366e2984b2a5&#x2F;stubs&#x2F;dateparser&#x2F;dateparser&#x2F;__init__.pyi&quot;&gt;here&lt;&#x2F;a&gt; is an example of a &lt;code&gt;.pyi&lt;&#x2F;code&gt; file generated by the stubgen tool for the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;scrapinghub&#x2F;dateparser&quot;&gt;dateparser&lt;&#x2F;a&gt; package.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;Any, Optional
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;parse(
&lt;&#x2F;span&gt;&lt;span&gt;    date_string: Any, 
&lt;&#x2F;span&gt;&lt;span&gt;    date_formats: Optional[Any] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;, 
&lt;&#x2F;span&gt;&lt;span&gt;    languages: Optional[Any] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;, 
&lt;&#x2F;span&gt;&lt;span&gt;    locales: Optional[Any] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;, 
&lt;&#x2F;span&gt;&lt;span&gt;    region: Optional[Any] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;, 
&lt;&#x2F;span&gt;&lt;span&gt;    settings: Optional[Any] = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;): &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Keep in mind, most types annotations will default to &lt;code&gt;Any&lt;&#x2F;code&gt;. You&#x27;ll need to update &lt;code&gt;pyi&lt;&#x2F;code&gt; files and write more precise types (We agree that &lt;code&gt;Any&lt;&#x2F;code&gt; everywhere is not really useful). &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hoefling&#x2F;typeshed&#x2F;blob&#x2F;855acb4da416375b0d4791be51bf0934b0ee9e29&#x2F;stubs&#x2F;dateparser&#x2F;dateparser&#x2F;__init__.pyi&quot;&gt;Here&lt;&#x2F;a&gt; is an example of the same stub file with more precise type annotations:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;datetime
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;sys
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;Set, Tuple
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;dateparser.date &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;DateDataParser
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;sys.version_info &amp;gt;= (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;Literal, TypedDict
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;typing_extensions &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;Literal, TypedDict
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;__version__: str
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;_default_parser: DateDataParser
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;_Part = Literal[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;day&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;month&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;year&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;_ParserKind = Literal[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;timestamp&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;relative-time&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;custom-formats&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;absolute-time&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;no-spaces-time&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;_Settings(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;TypedDict&lt;&#x2F;span&gt;&lt;span&gt;, total=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;False&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    DATE_ORDER: str
&lt;&#x2F;span&gt;&lt;span&gt;    PREFER_LOCALE_DATE_ORDER: bool
&lt;&#x2F;span&gt;&lt;span&gt;    TIMEZONE: str
&lt;&#x2F;span&gt;&lt;span&gt;    TO_TIMEZONE: str
&lt;&#x2F;span&gt;&lt;span&gt;    RETURN_AS_TIMEZONE_AWARE: bool
&lt;&#x2F;span&gt;&lt;span&gt;    PREFER_DAY_OF_MONTH: Literal[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;current&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;first&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;last&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;    PREFER_DATES_FROM: Literal[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;current_period&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;future&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;past&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;    RELATIVE_BASE: datetime.datetime
&lt;&#x2F;span&gt;&lt;span&gt;    STRICT_PARSING: bool
&lt;&#x2F;span&gt;&lt;span&gt;    REQUIRE_PARTS: list[_Part]
&lt;&#x2F;span&gt;&lt;span&gt;    SKIP_TOKENS: list[str]
&lt;&#x2F;span&gt;&lt;span&gt;    NORMALIZE: bool
&lt;&#x2F;span&gt;&lt;span&gt;    RETURN_TIME_AS_PERIOD: bool
&lt;&#x2F;span&gt;&lt;span&gt;    PARSERS: list[_ParserKind]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;parse(
&lt;&#x2F;span&gt;&lt;span&gt;    date_string: str,
&lt;&#x2F;span&gt;&lt;span&gt;    date_formats: list[str] | Tuple[str] | Set[str] | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    languages: list[str] | Tuple[str] | Set[str] | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    locales: list[str] | Tuple[str] | Set[str] | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    region: str | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    settings: _Settings | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; datetime.datetime | &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Do we agree that the :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;parse function parameters are more precise.&lt;&#x2F;li&gt;
&lt;li&gt;settings parameter is annotated with a more detailed type.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#6&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;li&gt;returned value is more precise.&lt;&#x2F;li&gt;
&lt;li&gt;refactoring of this function will be easier.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;h3 id=&quot;2-type-checking&quot;&gt;2. Type checking:&lt;&#x2F;h3&gt;
&lt;p&gt;Before running your tests, before running your program, Mypy can detect &lt;em&gt;some types&lt;&#x2F;em&gt; of bugs:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;what2.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I pretend &lt;code&gt;foo&lt;&#x2F;code&gt; should return a &lt;code&gt;string&lt;&#x2F;code&gt;, yet, there are cases where foo does return &lt;code&gt;None&lt;&#x2F;code&gt;. That should be fixed. Notice how, the program is running fine. Mypy will type check the program and tell you what&#x27;s wrong. Mypy won&#x27;t stop you from running the program.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion:&lt;&#x2F;h2&gt;
&lt;p&gt;Most people, including myself, don&#x27;t work on projects of this size (&lt;a href=&quot;https:&#x2F;&#x2F;dropbox.tech&#x2F;application&#x2F;our-journey-to-type-checking-4-million-lines-of-python&quot;&gt;4 million lines of Python code&lt;&#x2F;a&gt;), and hence have not to deal with the constraints of such a big code base.&lt;&#x2F;p&gt;
&lt;p&gt;Most people can perfectly write their Python programs without using type annotations. Mypy is just another tool inside your toolbox. I just want you to try, that will certainly make you a better software developer.&lt;&#x2F;p&gt;
&lt;p&gt;In the &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;stcmp2&#x2F;&quot;&gt;next article&lt;&#x2F;a&gt;, I will talk a little bit more about the actual process I&#x27;ve followed for adding type annotations to the RQL package.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;to-learn-more-about-this-topic&quot;&gt;To learn more about this topic:&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;typing.html&quot;&gt;Python typing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;tube.incognet.io&#x2F;watch?v=pJOmlFf5Je4&quot;&gt;What Python can learn from Haskell&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=hTrjTAPnA_k&quot;&gt;Type hinting (and mypy)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;4&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Which, by the way, is where you&#x27;ll find more interesting answers than what&#x27;s inside the documentation, imho.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;6&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Yes. I won&#x27;t deny, there is suddenly more lines to &lt;strong&gt;read&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Elephant in the room (part 1)</title>
        <published>2021-05-25T03:40:17+00:00</published>
        <updated>2021-05-25T03:40:17+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/eitr/"/>
        <id>https://nskm.xyz/posts/eitr/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/eitr/">&lt;p&gt;I&#x27;m living in a Continent where (&lt;em&gt;it sounds like&lt;&#x2F;em&gt;) nobody really cares about software freedom, data privacy, surveillance. I guess, people here are simply too busy trying to stay &lt;a href=&quot;https:&#x2F;&#x2F;www.africanews.com&#x2F;2021&#x2F;05&#x2F;29&#x2F;second-volcano-erupts-in-eastern-democratic-republic-of-congo&#x2F;&quot;&gt;alive&lt;&#x2F;a&gt;, not enough time to think about FOSS. Or maybe they&#x27;re simply confused, maybe they simply don&#x27;t know.&lt;&#x2F;p&gt;
&lt;p&gt;The topic is wide, it&#x27;s easy to digress, and I&#x27;m not sure about the best way to tackle it (&lt;em&gt;consider this to be a first draft, updates will come&lt;&#x2F;em&gt;). Let&#x27;s say it&#x27;s just an attempt, an effort, to &lt;em&gt;at least&lt;&#x2F;em&gt; address the issue.&lt;&#x2F;p&gt;
&lt;br&gt;
Okay. Let me put you in the context...
&lt;br&gt;
&lt;h1 id=&quot;will-you-be-okay-with-anybody-trying-to&quot;&gt;&lt;em&gt;Will you be okay with anybody trying to:&lt;&#x2F;em&gt;&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;Fix any of your furnitures.&lt;&#x2F;li&gt;
&lt;li&gt;Take you anywhere you want.&lt;&#x2F;li&gt;
&lt;li&gt;Offer you any food you want.&lt;&#x2F;li&gt;
&lt;li&gt;Pay for all your phone, sms, mail bills.&lt;&#x2F;li&gt;
&lt;li&gt;Let you watch any movie, any film, any show.&lt;&#x2F;li&gt;
&lt;li&gt;Alert you about something every 5mn.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;h1 id=&quot;and-in-exchange-the-same-person&quot;&gt;&lt;em&gt;And in exchange the same person:&lt;&#x2F;em&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;Won&#x27;t ask you for any money, nothing, he&#x27;ll just keep a tiny tiny list of all:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the furnitures in your house?&lt;&#x2F;li&gt;
&lt;li&gt;the places you visit?&lt;&#x2F;li&gt;
&lt;li&gt;the foods you eat?&lt;&#x2F;li&gt;
&lt;li&gt;the conversations you had?&lt;&#x2F;li&gt;
&lt;li&gt;the movies you watched?&lt;&#x2F;li&gt;
&lt;li&gt;the time he notified you? The reason he notified you?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;h1 id=&quot;do-we-agree-that-you-won-t-be-okay&quot;&gt;&lt;em&gt;Do we agree that you won&#x27;t be okay?&lt;&#x2F;em&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;em&gt;In standard conditions for temperature and pressure&lt;&#x2F;em&gt;, you won&#x27;t be okay with anybody offering you the deal above because (&lt;em&gt;among many other reasons&lt;&#x2F;em&gt;):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;you don&#x27;t want anybody to access your &lt;strong&gt;private space&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;you want to keep a certain level of &lt;strong&gt;autonomy&lt;&#x2F;strong&gt;, &lt;strong&gt;independance&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;you want to preserve your physical &lt;strong&gt;integrity&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;h1 id=&quot;interestingly&quot;&gt;&lt;em&gt;Interestingly:&lt;&#x2F;em&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;It sounds like, nobody want me to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;put a webcam and a microphone in their house.&lt;&#x2F;li&gt;
&lt;li&gt;have the key to their house.&lt;&#x2F;li&gt;
&lt;li&gt;follow them.&lt;&#x2F;li&gt;
&lt;li&gt;take picture of them or recording them.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Yet, most of the same people are using all kinds of &lt;em&gt;&quot;privacy invading&quot;&lt;&#x2F;em&gt; technologies on a daily basis:  &lt;a href=&quot;https:&#x2F;&#x2F;www.forbes.com&#x2F;sites&#x2F;kateoflahertyuk&#x2F;2019&#x2F;07&#x2F;28&#x2F;apple-siri-eavesdropping-puts-millions-of-users-at-risk&quot;&gt;Siri&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.cnet.com&#x2F;home&#x2F;smart-home&#x2F;alexa-and-google-voice-assistants-app-exploits-left-it-vulnerable-to-eavesdropping&#x2F;&quot;&gt;Alexa&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.vrt.be&#x2F;vrtnws&#x2F;en&#x2F;2019&#x2F;07&#x2F;10&#x2F;google-employees-are-eavesdropping-even-in-flemish-living-rooms&#x2F;&quot;&gt;Google&lt;&#x2F;a&gt;. I won&#x27;t even talk about &lt;a href=&quot;https:&#x2F;&#x2F;www.dw.com&#x2F;en&#x2F;samsung-admits-smart-tv-may-be-eavesdropping&#x2F;a-18246372&quot;&gt;smart TVs&lt;&#x2F;a&gt;, nor &lt;a href=&quot;https:&#x2F;&#x2F;www.reuters.com&#x2F;article&#x2F;us-eu-facebook-dataprotection-idUSKCN1UO1B4&quot;&gt;Facebook&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h1 id=&quot;any-reasons-that-let-us-give-our-datas-to-the-tech-giants&quot;&gt;&lt;em&gt;Any reasons that let us give our datas to the Tech Giants?&lt;&#x2F;em&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;People use privacy invading software for maaaaany reasons that can be understood.
&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There is the &quot;I need to figure out what to eat today&quot; reason. Present all over the world, especially for the poorer people. Even more true in the Black continent.&lt;&#x2F;p&gt;
&lt;p&gt;There is the fact that &lt;strong&gt;implications&lt;&#x2F;strong&gt; (of using privacy invading software) &lt;strong&gt;are invisible&lt;&#x2F;strong&gt;, not obvious. While the benefits are immediate, concrete, observable.&lt;&#x2F;p&gt;
&lt;p&gt;Terms of Service are, &lt;em&gt;most of the time&lt;&#x2F;em&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;tosdr.org&#x2F;en&#x2F;service&#x2F;182&quot;&gt;confusing&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;tosdr.org&#x2F;fr&#x2F;service&#x2F;217&quot;&gt;difficult&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;tosdr.org&#x2F;fr&#x2F;service&#x2F;198&quot;&gt;blurry&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;There is also the &quot;I use it because people around me are using it&quot; reason. People are moved by &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Network_effect&quot;&gt;those around&lt;&#x2F;a&gt; them and wish to fit in as quickly as possible, as simply as possible.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Henrik_Ibsen&quot;&gt;Henrik Ibsen&lt;&#x2F;a&gt; said &lt;em&gt;&quot;A thousand words leave not the same deep impression as does a single deed&quot;&lt;&#x2F;em&gt;. And I definitely agree with him:&lt;&#x2F;p&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;vicious-cycle.42e644fb1aedfddb.png&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;theconversation.com&#x2F;heres-how-tech-giants-profit-from-invading-our-privacy-and-how-we-can-start-taking-it-back-120078&quot;&gt;Source&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h1 id=&quot;do-you-know-that&quot;&gt;&lt;em&gt;Do you know that:&lt;&#x2F;em&gt;&lt;&#x2F;h1&gt;
&lt;ol&gt;
&lt;li&gt;Your right to physical integrity was &lt;em&gt;already&lt;&#x2F;em&gt; affirmed in 1222, &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Kouroukan_Fouga#Contents&quot;&gt;inside the Manden Charter&lt;&#x2F;a&gt;, article 5:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Everybody has a right to life and to the &lt;strong&gt;preservation of physical integrity&lt;&#x2F;strong&gt;. [...]&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Your right to privacy was affirmed in 1948 by the &lt;a href=&quot;https:&#x2F;&#x2F;www.un.org&#x2F;en&#x2F;about-us&#x2F;universal-declaration-of-human-rights&quot;&gt;Universal Declaration of Human Rights&lt;&#x2F;a&gt;, article 12:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;blockquote&gt;
&lt;p&gt;No one shall be subjected to &lt;strong&gt;arbitrary interference&lt;&#x2F;strong&gt; with his privacy, family, home or correspondence, nor to attacks upon his honour and reputation. Everyone has the right to the protection of the law against such interference or attacks.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Within the &lt;a href=&quot;https:&#x2F;&#x2F;www.echr.coe.int&#x2F;documents&#x2F;convention_eng.pdf&quot;&gt;European Convention on Human Rights&lt;&#x2F;a&gt;, in the article 8, we can read:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Right to respect for private and family life.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Everyone has the right to respect for his private and family life, his home and his correspondence.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;There shall be &lt;strong&gt;no interference by a public authority&lt;&#x2F;strong&gt; with the exercise of this right except such as is in accordance with the law and is necessary in a democratic society in the interests of national security, public safety or the economic well-being of the country, for the prevention of disorder or crime, for the protection of health or morals, or for the protection of the rights and freedoms of others.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;blockquote&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;www.law.cornell.edu&#x2F;constitution&quot;&gt;U.S. constitution&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;constitution.congress.gov&#x2F;constitution&#x2F;amendment-4&#x2F;&quot;&gt;Fourth Amendment&lt;&#x2F;a&gt; states that:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;blockquote&gt;
&lt;p&gt;The right of the people to be secure in their persons, houses, papers, and effects, &lt;strong&gt;against unreasonable searches and seizures&lt;&#x2F;strong&gt;, shall not be violated, and no Warrants shall issue, but upon probable cause, supported by Oath or affirmation, and particularly describing the place to be searched, and the persons or things to be seized.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;br&gt;
&lt;p&gt;The point seems to be: &lt;strong&gt;Every human being has a right to privacy, and this right should not be violated.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;what-is-privacy&quot;&gt;&lt;em&gt;What is privacy?&lt;&#x2F;em&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;I was not able to find a fixed, simple, perfect, static definition of &lt;a href=&quot;https:&#x2F;&#x2F;www.nolo.com&#x2F;dictionary&#x2F;right-to-privacy-term.html&quot;&gt;privacy&lt;&#x2F;a&gt;. The definition may vary from one country to another, from one constitution to another, from one period of time to another.&lt;&#x2F;p&gt;
&lt;p&gt;But I guess we can agree that privacy is any information that intrudes into the intimacy of the individual. &lt;em&gt;Right&lt;&#x2F;em&gt;? Privacy is that thing which is essential to the protection of our dignity as Human Being. &lt;em&gt;Right&lt;&#x2F;em&gt;?  Anything that is directly related to :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;your personal space, your house, your image,&lt;&#x2F;li&gt;
&lt;li&gt;your financial status, your medical status,&lt;&#x2F;li&gt;
&lt;li&gt;your religious, political, &lt;em&gt;or even sexual&lt;&#x2F;em&gt; orientations,&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Privacy is the fundamental way to protect yourself&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;some-of-the-solutions-we-can-explore&quot;&gt;&lt;em&gt;Some of the solutions we can explore:&lt;&#x2F;em&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;How do we defend ourselves and our friends from privacy invading technologies? What can we do to safeguard our personal privacy. What are the ways we can use to better protect ourselves when going online? What are the alternatives to the privacy invading software? I&#x27;ll talk about the solutions in the next &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;wmdop&#x2F;&quot;&gt;article&lt;&#x2F;a&gt; (&lt;em&gt;coming soon&lt;&#x2F;em&gt;).&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h1 id=&quot;no-i-m-not&quot;&gt;&lt;em&gt;No, I&#x27;m not:&lt;&#x2F;em&gt;&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;Saying that I&#x27;ve all the answers.&lt;&#x2F;li&gt;
&lt;li&gt;Saying that you should do as I say.&lt;&#x2F;li&gt;
&lt;li&gt;Asking you to close all your accounts.&lt;&#x2F;li&gt;
&lt;li&gt;Asking you to go back to the stone age.&lt;&#x2F;li&gt;
&lt;li&gt;Trying to make you affraid of technology.&lt;&#x2F;li&gt;
&lt;li&gt;Saying that I&#x27;ve found all the alternatives.&lt;&#x2F;li&gt;
&lt;li&gt;Saying that migrating from privacy invading software will be an easy task.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;h1 id=&quot;what-i-m-asking-you&quot;&gt;&lt;em&gt;What I&#x27;m asking you:&lt;&#x2F;em&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;Completely shuting down all the Tech Giants won&#x27;t be an easy task. It cannot be done within the snap of a finger &lt;em&gt;(I wish it &lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=TWB31WFomz4&quot;&gt;could&lt;&#x2F;a&gt;)&lt;&#x2F;em&gt;. Let&#x27;s stay optimistic, there is still some actionable steps we can take to help:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Ask yourself :
&lt;ul&gt;
&lt;li&gt;Why are you using those platforms?&lt;&#x2F;li&gt;
&lt;li&gt;What are the services you really need?&lt;&#x2F;li&gt;
&lt;li&gt;Is there any alternatives? (Respecting your privacy).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Be aware:
&lt;ul&gt;
&lt;li&gt;of the risks, of the pros &amp;amp; cons.&lt;&#x2F;li&gt;
&lt;li&gt;that if it&#x27;s free, you&#x27;re probably the &lt;a href=&quot;https:&#x2F;&#x2F;ethannonsequitur.com&#x2F;wp-content&#x2F;uploads&#x2F;2011&#x2F;09&#x2F;facebook-and-you-pigs.jpg&quot;&gt;product&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Ask for more:
&lt;ul&gt;
&lt;li&gt;Transparency to all those platforms.&lt;&#x2F;li&gt;
&lt;li&gt;Regulation &amp;amp; protection to your leaders, your governments.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Spark conversation, everywhere.&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;h1 id=&quot;interesting-links&quot;&gt;Interesting links:&lt;&#x2F;h1&gt;
&lt;p&gt;This topic is too wide to be covered entirely in this tiny article. I really hope you&#x27;re learned something. I strongly recommend the following links for a better exploration and understanding of the topic.&lt;&#x2F;p&gt;
&lt;p&gt;The following is a list of resources you should &lt;em&gt;download, browse &amp;amp; share&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#&quot;&gt;Enemy of the State&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.killswitchthefilm.com&#x2F;&quot;&gt;Killswitch&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;yewtu.be&#x2F;watch?v=ZHl0WI32XkY&quot;&gt;We are legion&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;#&quot;&gt;Terms and conditions may apply&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;citizenfourfilm.com&#x2F;&quot;&gt;Citizenfour&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.thesocialdilemma.com&#x2F;&quot;&gt;Social dilemma&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.thegreathack.com&#x2F;&quot;&gt;The great hack&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;snowdenfilm.com&#x2F;&quot;&gt;Snowden&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.yewtu.be&#x2F;watch?v=YXmMtbgdces&quot;&gt;Nos données personnelles valent de l&#x27;or&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;activism.net&#x2F;cypherpunk&#x2F;manifesto.html&quot;&gt;A Cypherpunk&#x27;s Manifesto&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.yewtu.be&#x2F;watch?v=IWzmYE60_dc&quot;&gt;Macron trahit la « start-up nation », les gafam raflent la mise&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;thanks&quot;&gt;Thanks:&lt;&#x2F;h1&gt;
&lt;p&gt;Special &lt;a href=&quot;https:&#x2F;&#x2F;www.meme-arsenal.com&#x2F;memes&#x2F;379eb2a9776a3bbaac72286e3d857cbf.jpg&quot;&gt;thanks&lt;&#x2F;a&gt; to Orbifx, &lt;a href=&quot;https:&#x2F;&#x2F;mastodon.scot&#x2F;@orbifx&quot;&gt;the Nature&#x27;s emissary&lt;&#x2F;a&gt;, and  &lt;a href=&quot;https:&#x2F;&#x2F;mastodon.social&#x2F;@travis_kalanick&quot;&gt;Travis Kalanick&lt;&#x2F;a&gt;. They both gave me interesting ideas to help me finish this article.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h1 id=&quot;do-not-forget&quot;&gt;Do not forget:&lt;&#x2F;h1&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;real-power-is-people.815a6f16ec1b60fc.jpg&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Django single file project. Again</title>
        <published>2020-07-10T01:09:16+00:00</published>
        <updated>2020-07-10T01:09:16+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/dsfpa/"/>
        <id>https://nskm.xyz/posts/dsfpa/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/dsfpa/">&lt;p&gt;This article is a follow up on the &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;dsfp&#x2F;&quot;&gt;one&lt;&#x2F;a&gt; I&#x27;ve written few years
ago. Special shoutout and thanks and hugs and kudos to &lt;a href=&quot;http:&#x2F;&#x2F;buzzi.me&#x2F;&quot;&gt;Javier
Buzzi&lt;&#x2F;a&gt; for taking the time to &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;kingbuzzman&#x2F;d7859d9734b590e52fad787d19c34b52&quot;&gt;improve&lt;&#x2F;a&gt; the original script.&lt;&#x2F;p&gt;
&lt;p&gt;TL;DR: &lt;a href=&quot;https:&#x2F;&#x2F;bin.nskm.xyz&#x2F;pastes&#x2F;ee784daff75aae62&quot;&gt;download old version&lt;&#x2F;a&gt; &amp;amp; &lt;a href=&quot;https:&#x2F;&#x2F;bin.nskm.xyz&#x2F;pastes&#x2F;c4434741122bec0f&quot;&gt;download new version&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;br &#x2F;&gt;
&lt;h2 id=&quot;very-important-disclaimer&quot;&gt;VERY IMPORTANT DISCLAIMER&lt;&#x2F;h2&gt;
&lt;p&gt;The content associated with mlvin.xyz may be very offensive to some people. I&#x27;ve lost the ownership of mlvin.xyz a very long time ago, sad situation. I&#x27;m not anymore linked to this domain name, nor to the content hosted on this website. &lt;em&gt;By the way F*** OVH&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-are-those-improvements&quot;&gt;What are those improvements?&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;application-label&quot;&gt;Application label?&lt;&#x2F;h3&gt;
&lt;p&gt;Our models are not defined as in a classical Django application. So,
each model should declare which app it belongs to. You can read more
about app_label Meta option &lt;a href=&quot;https:&#x2F;&#x2F;docs.djangoproject.com&#x2F;en&#x2F;3.0&#x2F;ref&#x2F;models&#x2F;options&#x2F;#django.db.models.Options.app%5Flabel&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The problem with the first script was duplication:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Author(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;models.Model&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    name = models.CharField(max_length=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Meta:
&lt;&#x2F;span&gt;&lt;span&gt;        app_label = APP_LABEL
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Book(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;models.Model&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    author = models.ForeignKey(Author, related_name=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;books&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    title = models.CharField(max_length=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;400&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Meta:
&lt;&#x2F;span&gt;&lt;span&gt;        app_label = APP_LABEL
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We want to define app_label once and for all our models:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# The current name of the file, which will be the name of our app
&lt;&#x2F;span&gt;&lt;span&gt;APP_LABEL, _ = os.path.splitext(os.path.basename(os.path.abspath(__file__)))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, we need to overwrite the Django function in charge of:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;looking for an application configuration&lt;&#x2F;li&gt;
&lt;li&gt;attach the model to the found&#x2F;correct application configuration.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This function is named &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;django&#x2F;django&#x2F;blob&#x2F;stable&#x2F;3.0.x&#x2F;django&#x2F;apps&#x2F;registry.py#L243&quot;&gt;get_containing_app_config&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;get_containing_app_config(module):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;module == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;__main__&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# if inside single file project,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# retrieve the application configuration using APP_LABEL variable
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;apps.get_app_config(APP_LABEL)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# otherwise, do as you always do
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;apps._get_containing_app_config(module)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# save the original function
&lt;&#x2F;span&gt;&lt;span&gt;apps._get_containing_app_config = apps.get_containing_app_config
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# ask Django to use our custom function
&lt;&#x2F;span&gt;&lt;span&gt;apps.get_containing_app_config = get_containing_app_config
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;migrations-folder&quot;&gt;Migrations folder?&lt;&#x2F;h3&gt;
&lt;p&gt;There is a Django settings named &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;django&#x2F;django&#x2F;blob&#x2F;stable&#x2F;3.0.x&#x2F;django&#x2F;conf&#x2F;global_settings.py#L616&quot;&gt;MIGRATION_MODULE&lt;&#x2F;a&gt;. According to the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;django&#x2F;django&#x2F;blob&#x2F;stable&#x2F;3.0.x&#x2F;docs&#x2F;ref&#x2F;settings.txt#L2021&quot;&gt;documentation&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;A dictionary specifying the package where migration modules can be found on a per-app basis. The  default value of this setting is an empty dictionary, but the default package name for migration modules is ``migrations``.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;br&gt;
&lt;p&gt;In the first version of the script, all the migrations were put in a folder named &lt;code&gt;migrations&lt;&#x2F;code&gt;. With the following configuration, we can:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;name the migration folder how we want.&lt;&#x2F;li&gt;
&lt;li&gt;make sure that we have one migration folder per application.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Where migrations folder need to be created
&lt;&#x2F;span&gt;&lt;span&gt;APP_MIGRATION_MODULE = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;_migrations&amp;#39; &lt;&#x2F;span&gt;&lt;span&gt;% APP_LABEL
&lt;&#x2F;span&gt;&lt;span&gt;APP_MIGRATION_PATH = os.path.join(BASE_DIR, APP_MIGRATION_MODULE)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Create the migration folder
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# and a __init__.py file if necessary:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if not &lt;&#x2F;span&gt;&lt;span&gt;os.path.exists(APP_MIGRATION_PATH):
&lt;&#x2F;span&gt;&lt;span&gt;    os.makedirs(APP_MIGRATION_PATH)
&lt;&#x2F;span&gt;&lt;span&gt;    open(os.path.join(APP_MIGRATION_PATH, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;__init__.py&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;w&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;).close()
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We also took the time to update the Django settings, somewhere inside the call to &lt;code&gt;settings.configure function&lt;&#x2F;code&gt;, you&#x27;ll find:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Django needs to be told where is the migration module
&lt;&#x2F;span&gt;&lt;span&gt;MIGRATION_MODULES={APP_LABEL: APP_MIGRATION_MODULE},
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;fake-modules&quot;&gt;Not so fake modules?&lt;&#x2F;h3&gt;
&lt;p&gt;A correctly configured Django application should normally have a &lt;code&gt;model modules&lt;&#x2F;code&gt;, a &lt;code&gt;urls modules&lt;&#x2F;code&gt; and a &lt;code&gt;tests module&lt;&#x2F;code&gt;. Python provides us with an interesting  &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;types.html#types.ModuleType&quot;&gt;class&lt;&#x2F;a&gt;: &lt;code&gt;types.ModuleType&lt;&#x2F;code&gt;, that will help us create a module, &lt;em&gt;you guessed it&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Used so you can do &amp;#39;from &amp;lt;name of file&amp;gt;.models import *&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;models_module = ModuleType(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;.models&amp;#39; &lt;&#x2F;span&gt;&lt;span&gt;% (APP_LABEL))
&lt;&#x2F;span&gt;&lt;span&gt;tests_module = ModuleType(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;.tests&amp;#39; &lt;&#x2F;span&gt;&lt;span&gt;% (APP_LABEL))
&lt;&#x2F;span&gt;&lt;span&gt;urls_module = ModuleType(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;.urls&amp;#39; &lt;&#x2F;span&gt;&lt;span&gt;% (APP_LABEL))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# we created the urlpatterns list earlier,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# let&amp;#39;s attach this variable to the urls_module:
&lt;&#x2F;span&gt;&lt;span&gt;urls_module.urlpatterns = urlpatterns
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# A model module needs to have classes that inherits from models.Model
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# let&amp;#39;s correctly add all our models we defined earlier
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# as attributes to the models_module:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;variable_name, value &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;list(locals().items()):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# We are only interested in models
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;inspect.isclass(value) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;and &lt;&#x2F;span&gt;&lt;span&gt;issubclass(value, models.Model):
&lt;&#x2F;span&gt;&lt;span&gt;        setattr(models_module, variable_name, value)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Setup the fake modules
&lt;&#x2F;span&gt;&lt;span&gt;sys.modules[models_module.__name__] = models_module
&lt;&#x2F;span&gt;&lt;span&gt;sys.modules[urls_module.__name__] = urls_module
&lt;&#x2F;span&gt;&lt;span&gt;sys.modules[APP_LABEL].models = models_module
&lt;&#x2F;span&gt;&lt;span&gt;sys.modules[APP_LABEL].urls = urls_module
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;going-further&quot;&gt;Going further?&lt;&#x2F;h3&gt;
&lt;p&gt;I really hope you&#x27;ve learned something, I did \o&#x2F;. You may want to browse some of the gists kept by &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;search?q=mlvin&quot;&gt;Javier Buzzi&lt;&#x2F;a&gt;.
&lt;br&gt;&lt;br&gt;
You may also be really interested by the work done for  &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;zenwalker&#x2F;django-micro&quot;&gt;django-micro&lt;&#x2F;a&gt; a lightweight wrapper around Django that turns it into a microframework.
&lt;br&gt;&lt;br&gt;
If you have any kind of interesting improvements, advices, suggestions, please send me an email, or post a comment on &lt;a href=&quot;https:&#x2F;&#x2F;mastodon.social&#x2F;@lemeteore&#x2F;104489090816400323&quot;&gt;Mastodon&lt;&#x2F;a&gt;. &lt;em&gt;Still not took the time to install a comment system, shame on me&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;o&#x2F;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Free and Open Source Software</title>
        <published>2017-04-04T00:00:00+00:00</published>
        <updated>2017-04-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/foss/"/>
        <id>https://nskm.xyz/posts/foss/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/foss/">&lt;p&gt;I&#x27;m often asked why do I prefer to use free software in places (Dakar, Libreville, Kinshasa, ...), where basically every human being is using closed source and proprietary software? Here are some of the reasons.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h3 id=&quot;not-being-able-to-pay-for-a-license&quot;&gt;&lt;strong&gt;Not being able to pay for a license&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Learning informatics was equivalent to installing a bunch of software requiring me to pay for a license. And coming from a very modest family, paying for a license was not an option. I&#x27;ve never really been able to explain to my parent that&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;I need to pay, via internet, using a credit card&lt;&#x2F;li&gt;
&lt;li&gt;a company located somewhere in the world, I don&#x27;t even know where&lt;&#x2F;li&gt;
&lt;li&gt;to get the permission to use such an abstract thing like a software&lt;&#x2F;li&gt;
&lt;li&gt;for some time, then I&#x27;ll have to pay again, to renew the permission&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;h3 id=&quot;tired-of-looking-for-the-crack&quot;&gt;&lt;strong&gt;Tired of looking for the crack&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Not being able to pay for the license, the remaining choice was to look for the crack. that was the most easy way to get the software you want to use. But in the mean time, That was a very difficult task, always browsing the internet, looking for the product keys, the key generator, the patch, the full activator, etc... It was time consuming, and boring as editors are always trying to make it more and more difficult.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h3 id=&quot;trying-to-be-a-good-citizen&quot;&gt;&lt;strong&gt;Trying to be a good citizen&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Even if they should, most people often do not feel bad about using cracked software. After all, there were no physical harm, no shoplifting, no unlawful entry into a building, no indiscriminate taking of goods. Why feeling bad about it?&lt;&#x2F;p&gt;
&lt;p&gt;Theft, from &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Theft&quot;&gt;Wikipedia&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In common usage, a theft is the illegal taking of another person&#x27;s property or services without that person&#x27;s permission or consent with the intent to deprive the rightful owner of it.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Property, from &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Property#Types_of_property&quot;&gt;Wikepedia&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Important widely recognized types of property include real property (the combination of land and any improvements to or on the land), personal property (physical possessions belonging to a person), private property (property owned by legal persons, business entities or individual natural persons), public property (state owned or publicly owned and available possessions) and intellectual property (exclusive rights over artistic creations, inventions, etc.), although the last is not always as widely recognized or enforced.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;br&gt;
Above are the main reasons why I chose free and open source software. You can actually close this page, and go back to your awesome life, **thanks for reading**. But there is more.
&lt;br&gt;
&lt;h3 id=&quot;the-free-and-open-source-software-philosophy-promotes-values-that-go-beyond-software&quot;&gt;&lt;strong&gt;The free and open source software philosophy promotes values that go beyond software&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;It&#x27;s about the right to &lt;em&gt;own&lt;&#x2F;em&gt; an item, &lt;em&gt;to use it for any purpose&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;It&#x27;s about the right to &lt;em&gt;study&lt;&#x2F;em&gt; how this item is made&lt;&#x2F;li&gt;
&lt;li&gt;It&#x27;s about the right to &lt;em&gt;customize&lt;&#x2F;em&gt; this item&lt;&#x2F;li&gt;
&lt;li&gt;It&#x27;s about the right to &lt;em&gt;share&lt;&#x2F;em&gt; the item modified or not, with whoever you want&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;h3 id=&quot;fine-can-we-have-some-real-life-examples-please&quot;&gt;&lt;strong&gt;Fine, can we have some real life examples please?&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;From &lt;a href=&quot;https:&#x2F;&#x2F;www.softwareheritage.org&#x2F;mission&#x2F;heritage&#x2F;&quot;&gt;Software Heritage&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Software controls the electronic equipment embedded in the machines we use to travel, communicate, trade and exchange. Software is just crucial for the proper operation of every large organizations. Software has enabled the emergence of new forms of social and political organizations. Software is essential to understand our society.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Maybe it&#x27;s not perceptible enough, but free and open source software is already &lt;a href=&quot;http:&#x2F;&#x2F;embedded-computing.com&#x2F;articles&#x2F;open-source-software-everywhere&#x2F;&quot;&gt;everywhere&lt;&#x2F;a&gt;. Here you are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Aerospace: Open Source Software projects from &lt;a href=&quot;https:&#x2F;&#x2F;code.nasa.gov&#x2F;&quot;&gt;NASA&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Automotive: &lt;a href=&quot;https:&#x2F;&#x2F;www.automotivelinux.org&quot;&gt;AGL&lt;&#x2F;a&gt; group, including lots of &lt;a href=&quot;https:&#x2F;&#x2F;www.automotivelinux.org&#x2F;about&#x2F;members&quot;&gt;automakers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Robotics: &lt;a href=&quot;https:&#x2F;&#x2F;www.osrfoundation.org&#x2F;osrf-projects&#x2F;&quot;&gt;Open Source Robotics Foundation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Healthcare: &lt;a href=&quot;http:&#x2F;&#x2F;www.open-emr.org&#x2F;&quot;&gt;Open-EMR&lt;&#x2F;a&gt;, &lt;a href=&quot;http:&#x2F;&#x2F;openmrs.org&#x2F;&quot;&gt;OpenMRS&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Education: &lt;a href=&quot;http:&#x2F;&#x2F;open-sankore.org&#x2F;en&quot;&gt;Open Sankoré&lt;&#x2F;a&gt;, an interactive whiteboard software.&lt;&#x2F;li&gt;
&lt;li&gt;Films: &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=eRsGyueVLvQ&quot;&gt;Sintel&lt;&#x2F;a&gt;, and many other open movies by &lt;a href=&quot;https:&#x2F;&#x2F;www.blender.org&#x2F;features&#x2F;projects&#x2F;&quot;&gt;Blender Foundation&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
It is no more about software, it is about **openess and freedom**.
&lt;br&gt;
The topic is actually very huge and deep, I&#x27;ve not even mentioned privacy, nor surveillance. I obviously won&#x27;t be able to cover the whole thing. 
&lt;h3 id=&quot;for-those-who-want-to-go-further-i-strongly-recommands-the-following-links&quot;&gt;&lt;strong&gt;For those who want to go further, I strongly recommands the following links:&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=xKsR5jWl1Tk&quot;&gt;Threats of data mining&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=8vOF8VsUwbA&quot;&gt;Freedom in the cloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;modernfarmer.com&#x2F;2016&#x2F;07&#x2F;right-to-repair&#x2F;&quot;&gt;Right to fix their own dang tractors&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;opensource.com&#x2F;article&#x2F;17&#x2F;4&#x2F;become-open-source-sustainer&quot;&gt;Why you should become an open source sustainer&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;anybox.fr&#x2F;blog&#x2F;pourquoi-l-open-source&quot;&gt;Pourquoi l&#x27;open source&lt;&#x2F;a&gt; (French)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Threads</title>
        <published>2017-03-08T04:30:25+00:00</published>
        <updated>2017-03-08T03:40:17+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/an-overwiew-on-threads/"/>
        <id>https://nskm.xyz/posts/an-overwiew-on-threads/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/an-overwiew-on-threads/">&lt;p&gt;I&#x27;ve written something about &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;processes-introduction&#x2F;&quot;&gt;processes&lt;&#x2F;a&gt; Let&#x27;s write some notes about threads. This is not really an introduction to threads. It&#x27;s more like a little bit of introspection, so we can have an interesting perspective of what are threads.&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-s-really-a-thread&quot;&gt;&lt;strong&gt;What&#x27;s really a thread?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Processes each have their own address space. Threads exist as subsets of a process. Threads are just multiple workers in the same &lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;processes-introduction&#x2F;&quot;&gt;virtual address space&lt;&#x2F;a&gt; all threads in a process share the same memory. They can also share open files and other resources. Within that VAS, each thread has its own ID, its own stack, its own program counter, its own independent flow of control, its own registers set. A thread is just a &lt;strong&gt;context of execution&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;threads-example.gif&quot; alt=&quot;Threads&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;br&gt;&lt;em&gt;Image from &lt;a href=&quot;http:&#x2F;&#x2F;mooneegee.blogspot.sn&#x2F;2015&#x2F;01&#x2F;os-thread.html&quot;&gt;mooneegee.blogspot.sn&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Next is a c script spawning two &lt;em&gt;posix&lt;&#x2F;em&gt; threads:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#define _GNU_SOURCE
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;pthread.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;unistd.h&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; sleep
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;sys&#x2F;syscall.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;sys&#x2F;types.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void * &lt;&#x2F;span&gt;&lt;span&gt;say_hello(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void* &lt;&#x2F;span&gt;&lt;span&gt;data){
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;str = (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char*&lt;&#x2F;span&gt;&lt;span&gt;)data;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; howmany = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; r = (rand() % &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  pid_t thread_id = syscall(__NR_gettid);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;while&lt;&#x2F;span&gt;&lt;span&gt;(howmany &amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;){
&lt;&#x2F;span&gt;&lt;span&gt;    sleep(r);
&lt;&#x2F;span&gt;&lt;span&gt;    howmany = howmany - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,str);
&lt;&#x2F;span&gt;&lt;span&gt;    printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;from thread &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%u&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt; and process &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%u&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;           thread_id, getpid());
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return NULL&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;){
&lt;&#x2F;span&gt;&lt;span&gt;  pthread_t t1,t2;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(getpid() &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    perror(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;unable to get pid&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;The main process id is &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, getpid());
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  pthread_create(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;t1,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span&gt;,say_hello,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;howdy&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  pthread_create(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;t2,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span&gt;,say_hello,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;hello&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  pthread_join(t1,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  pthread_join(t2,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;NULL&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;If we &lt;a href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man1&#x2F;strace.1.html&quot;&gt;strace&lt;&#x2F;a&gt; the execution of our c script:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ strace -f .&#x2F;bin&#x2F;how_to_thread
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The output will display lots of informations. And for what we are doing, the most interesting lines will look like this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;clone(child_stack=0x7f30fa9b8ff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f30fa9b99d0, tls=0x7f30fa9b9700, child_tidptr=0x7f30fa9b99d0) = 7450
&lt;&#x2F;span&gt;&lt;span&gt;Process 7450 attached
&lt;&#x2F;span&gt;&lt;span&gt;[pid  7449] clone(child_stack=0x7f30fa1b7ff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f30fa1b89d0, tls=0x7f30fa1b8700, child_tidptr=0x7f30fa1b89d0) = 7451
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h4 id=&quot;the-clone-system-call&quot;&gt;&lt;strong&gt;The clone() system call:&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;processes-introduction&#x2F;&quot;&gt;Processes&lt;&#x2F;a&gt; are created with the &lt;a href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man2&#x2F;fork.2.html&quot;&gt;fork()&lt;&#x2F;a&gt; system call. However, there is a separate system call, named &lt;a href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man2&#x2F;clone.2.html&quot;&gt;clone()&lt;&#x2F;a&gt; which is used for creating threads. It works like fork(), but it accepts a number of flags for adjusting its behavior so the child can share some parts of the parent&#x27;s execution context. Our c script made a call to clone() twice. And looking at &lt;em&gt;some&lt;&#x2F;em&gt; of the flags that have been passed, we can see that:&lt;&#x2F;p&gt;
&lt;p&gt;the caller and the child process:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;CLONE_VM: run in the &lt;strong&gt;same memory space&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;CLONE_FS: share the &lt;strong&gt;same filesystem information&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;CLONE_FILES: share the &lt;strong&gt;same file descriptor table&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;CLONE_THREAD: are placed in the &lt;strong&gt;same thread group&lt;&#x2F;strong&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;br&gt;
&lt;p&gt;Another interesting arguments passed to clone system call are &lt;code&gt;child_stack&lt;&#x2F;code&gt; and &lt;code&gt;tls&lt;&#x2F;code&gt;. From the man page, we can read &lt;a href=&quot;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man2&#x2F;clone.2.html&quot;&gt;somewhere&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The child_stack argument specifies the location of the stack used by the child process.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;And in &lt;a href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man2&#x2F;set_thread_area.2.html&quot;&gt;another part&lt;&#x2F;a&gt; of the man page:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;set a thread local storage (TLS) area&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Basically, we&#x27;re allocating a &lt;em&gt;personal stack&lt;&#x2F;em&gt; to each of our threads. But, we also give each thread, an access to a region of memory which is &lt;em&gt;not shared&lt;&#x2F;em&gt; with all other threads. Like one may do with Python using the &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;threading.html#thread-local-data&quot;&gt;threading.local&lt;&#x2F;a&gt; class.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;gdb-to-the-rescue&quot;&gt;&lt;strong&gt;GDB to the rescue&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Let&#x27;s have a confirmation using &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;gdb&#x2F;&quot;&gt;GDB&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;$ gdb .&#x2F;bin&#x2F;how_to_thread
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;First, we set two breakpoints, one at the start of the main function, another one at the start of the say_hello function:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;insert-breakpoints.png&quot; alt=&quot;insert breakpoints&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Then we start the debugged program: &lt;code&gt;r&lt;&#x2F;code&gt;, and list the mapped memory regions:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;info-proc-map1.png&quot; alt=&quot;info proc mappings&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So far, we see only one stack segment, the one used by the main process, that is because our threads are not yet created. Let&#x27;s continue a little bit (twice) with &lt;code&gt;c&lt;&#x2F;code&gt;, and you should be able to see something like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;info-proc-map2.png&quot; alt=&quot;info proc mappings&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This time, we can see three stacks in the same virtual address space. The ones used by our threads are &lt;code&gt;[stack:15074]&lt;&#x2F;code&gt; and &lt;code&gt;[stack:15075]&lt;&#x2F;code&gt;. GDB to inspect each thread&#x27;s stack:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;stacks.png&quot; alt=&quot;thread&amp;#39;s stack&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;LWP is an acronym and stands for Light Weight Process. Next to LWP is the thread ID assigned by the kernel to this thread. We see that each thread has its own stack, and inside each stack, the progress is different, while thread 3 is entering the say_hello function, thread 2 is in &lt;em&gt;nanosleep&lt;&#x2F;em&gt;. By the way nanosleep is also a &lt;a href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man2&#x2F;nanosleep.2.html&quot;&gt;system call&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here we are, a thread is indeed just a &lt;strong&gt;context of execution&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I won&#x27;t be able to cover the whole topic as it&#x27;s not an easy and small one. So you may find &lt;em&gt;really&lt;&#x2F;em&gt; interesting the following links:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man7&#x2F;pthreads.7.html&quot;&gt;Pthreads&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;lwn.net&#x2F;Articles&#x2F;7577&#x2F;&quot;&gt;Making Linux safe for pthreads&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.linfo.org&#x2F;context_switch.html&quot;&gt;Context switch&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;0xax.gitbooks.io&#x2F;linux-insides&#x2F;content&#x2F;SyncPrim&#x2F;sync-3.html&quot;&gt;Semaphores&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;turnoff.us&#x2F;geek&#x2F;dont-share-mutable-state&#x2F;&quot;&gt;The real reason not to share a mutable state&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Django single file project</title>
        <published>2017-01-12T17:17:17+00:00</published>
        <updated>2017-01-12T17:17:17+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/dsfp/"/>
        <id>https://nskm.xyz/posts/dsfp/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/dsfp/">&lt;h4 id=&quot;disclaimer&quot;&gt;&lt;strong&gt;Disclaimer?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;The main purpose of this post is learning. Like any tool we should explore and find ways to bend it until it breaks. You should &lt;em&gt;normally&lt;&#x2F;em&gt; not use those techniques in real life projects &lt;em&gt;right&lt;&#x2F;em&gt;? For this post, I&#x27;m assuming you&#x27;re using Django 1.10.4, and Python3.6.
&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;single-file&quot;&gt;&lt;strong&gt;Single file?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Before reading &lt;a href=&quot;http:&#x2F;&#x2F;shop.oreilly.com&#x2F;product&#x2F;0636920032502.do&quot;&gt;Lightweight Django&lt;&#x2F;a&gt;, I never tought it was possible to build a Django project in a single python file. For that kind of stuff, I usually think, &lt;a href=&quot;http:&#x2F;&#x2F;flask.pocoo.org&#x2F;&quot;&gt;Flask&lt;&#x2F;a&gt;, or &lt;a href=&quot;http:&#x2F;&#x2F;bottlepy.org&#x2F;docs&#x2F;dev&#x2F;&quot;&gt;Bottle&lt;&#x2F;a&gt;. And in fact, there are many &lt;a href=&quot;http:&#x2F;&#x2F;codecondo.com&#x2F;14-minimal-web-frameworks-for-python&#x2F;&quot;&gt;others&lt;&#x2F;a&gt;.
&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After reading the first chapter, I was a little bit disappointed. There were no Django &lt;a href=&quot;https:&#x2F;&#x2F;docs.djangoproject.com&#x2F;en&#x2F;1.10&#x2F;topics&#x2F;db&#x2F;models&#x2F;&quot;&gt;models&lt;&#x2F;a&gt; involved in the shown example. So, I try to find out if it was possible: &lt;strong&gt;a single file Django project with at least one application containing one model&lt;&#x2F;strong&gt;. I found some interesting links on the topic. But either it was for a very old version of Django, either I was obliged to install another package besides Django. After few days reading others people code, this is what I&#x27;ve done:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env python
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;os
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;sys
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.conf &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;settings
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;BASE_DIR = os.path.dirname(os.path.abspath(__file__))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;sys.path[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] = os.path.dirname(BASE_DIR)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# the current folder name will also be our app
&lt;&#x2F;span&gt;&lt;span&gt;APP_LABEL = os.path.basename(BASE_DIR)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;settings.configure(
&lt;&#x2F;span&gt;&lt;span&gt;    DEBUG=os.environ.get(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;DEBUG&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;on&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;) == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;on&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    SECRET_KEY=os.environ.get(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;SECRET_KEY&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, os.urandom(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;32&lt;&#x2F;span&gt;&lt;span&gt;)),
&lt;&#x2F;span&gt;&lt;span&gt;    ALLOWED_HOSTS=os.environ.get(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ALLOWED_HOSTS&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;localhost&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;).split(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;,&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;    ROOT_URLCONF=__name__,
&lt;&#x2F;span&gt;&lt;span&gt;    MIDDLEWARE=[
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.middleware.security.SecurityMiddleware&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.sessions.middleware.SessionMiddleware&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.middleware.common.CommonMiddleware&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.middleware.csrf.CsrfViewMiddleware&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.auth.middleware.AuthenticationMiddleware&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.messages.middleware.MessageMiddleware&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.middleware.clickjacking.XFrameOptionsMiddleware&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.middleware.locale.LocaleMiddleware&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        ],
&lt;&#x2F;span&gt;&lt;span&gt;    INSTALLED_APPS=[
&lt;&#x2F;span&gt;&lt;span&gt;        APP_LABEL,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.admin&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.auth&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.contenttypes&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.sessions&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.messages&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.staticfiles&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;rest_framework&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        ],
&lt;&#x2F;span&gt;&lt;span&gt;    STATIC_URL=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;static&#x2F;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    STATICFILES_DIRS=[
&lt;&#x2F;span&gt;&lt;span&gt;        os.path.join(BASE_DIR, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;static&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;    ],
&lt;&#x2F;span&gt;&lt;span&gt;    STATIC_ROOT=os.path.join(BASE_DIR, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;static_root&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;    MEDIA_ROOT=os.path.join(BASE_DIR, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;media&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;    MEDIA_URL=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;media&#x2F;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    TEMPLATES=[
&lt;&#x2F;span&gt;&lt;span&gt;        {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;BACKEND&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.template.backends.django.DjangoTemplates&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;DIRS&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [os.path.join(BASE_DIR, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;templates&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;),],
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;APP_DIRS&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;True&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;OPTIONS&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;context_processors&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.template.context_processors.debug&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.template.context_processors.i18n&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.template.context_processors.request&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.auth.context_processors.auth&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.template.context_processors.tz&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;                    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.messages.context_processors.messages&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;                ],
&lt;&#x2F;span&gt;&lt;span&gt;            },
&lt;&#x2F;span&gt;&lt;span&gt;        },
&lt;&#x2F;span&gt;&lt;span&gt;        ],
&lt;&#x2F;span&gt;&lt;span&gt;    DATABASES={
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;default&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ENGINE&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.db.backends.sqlite3&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;NAME&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: os.path.join(BASE_DIR, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;db.sqlite3&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;            }
&lt;&#x2F;span&gt;&lt;span&gt;        },
&lt;&#x2F;span&gt;&lt;span&gt;    REST_FRAMEWORK={
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;DEFAULT_PERMISSION_CLASSES&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;rest_framework.permissions.IsAdminUser&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        ],
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;PAGE_SIZE&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;10
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;django
&lt;&#x2F;span&gt;&lt;span&gt;django.setup()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.db &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;models
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.contrib &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;admin
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.db &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;models
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Create your models here.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Author(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;models.Model&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    name = models.CharField(max_length=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Meta:
&lt;&#x2F;span&gt;&lt;span&gt;        app_label = APP_LABEL
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Book(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;models.Model&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    author = models.ForeignKey(Author, related_name=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;books&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    title = models.CharField(max_length=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;400&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Meta:
&lt;&#x2F;span&gt;&lt;span&gt;        app_label = APP_LABEL
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;admin.site.register(Book)
&lt;&#x2F;span&gt;&lt;span&gt;admin.site.register(Author)
&lt;&#x2F;span&gt;&lt;span&gt;admin.autodiscover()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;rest_framework &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;serializers
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;BookSerializer(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;serializers.ModelSerializer&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;Meta:
&lt;&#x2F;span&gt;&lt;span&gt;        model = Book
&lt;&#x2F;span&gt;&lt;span&gt;        fields = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;__all__&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;rest_framework &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;viewsets
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span&gt;BooksViewSet(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#4ec9b0;&quot;&gt;viewsets.ReadOnlyModelViewSet&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    queryset = Book.objects.all()
&lt;&#x2F;span&gt;&lt;span&gt;    serializer_class = BookSerializer
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.conf.urls &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;url, include
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;rest_framework &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;routers
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.http &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;HttpResponse
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.contrib &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;admin
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;router = routers.DefaultRouter()
&lt;&#x2F;span&gt;&lt;span&gt;router.register(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;books&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, BooksViewSet)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;index(request):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;HttpResponse(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Hello&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;urlpatterns = [
&lt;&#x2F;span&gt;&lt;span&gt;    url(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;^&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;admin&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, admin.site.urls),
&lt;&#x2F;span&gt;&lt;span&gt;    url(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;^$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, index, name=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;homepage&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;    url(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;^&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;api&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, include(router.urls)),
&lt;&#x2F;span&gt;&lt;span&gt;    url(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;^&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;api-auth&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, include(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;rest_framework.urls&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,\
&lt;&#x2F;span&gt;&lt;span&gt;                                   namespace=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;rest_framework&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.core.wsgi &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;get_wsgi_application
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;__name__ == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;__main__&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.core.management &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;execute_from_command_line
&lt;&#x2F;span&gt;&lt;span&gt;    execute_from_command_line(sys.argv)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    get_wsgi_application()
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Everything related to &lt;a href=&quot;http:&#x2F;&#x2F;www.django-rest-framework.org&#x2F;&quot;&gt;Django REST Framework&lt;&#x2F;a&gt; is not mandatory. I was looking for &lt;a href=&quot;https:&#x2F;&#x2F;xkcd.com&#x2F;979&#x2F;&quot;&gt;interesting links&lt;&#x2F;a&gt; over the internet, and I found this question on &lt;a href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;q&#x2F;32866578&#x2F;4055832&quot;&gt;StackOverflow&lt;&#x2F;a&gt;. I saw this as an opportunity to kill two birds with one stone.
&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The above script was saved in a file named &lt;code&gt;single.py&lt;&#x2F;code&gt; in a folder named &lt;code&gt;lwdj&lt;&#x2F;code&gt;. But you can do as you feel, as soon as you respect the name of the file and the name of the current folder. The rest is known story:&lt;&#x2F;p&gt;
&lt;p&gt;Make the migrations for our application:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;(dj) ~&#x2F;...&#x2F;how_to_django&#x2F;lwdj  (master *%)
&lt;&#x2F;span&gt;&lt;span&gt;⤷ python single.py makemigrations lwdj
&lt;&#x2F;span&gt;&lt;span&gt;Migrations for &amp;#39;lwdj&amp;#39;:
&lt;&#x2F;span&gt;&lt;span&gt;  migrations&#x2F;0001_initial.py:
&lt;&#x2F;span&gt;&lt;span&gt;    - Create model Author
&lt;&#x2F;span&gt;&lt;span&gt;    - Create model Book
&lt;&#x2F;span&gt;&lt;span&gt;(dj) ~&#x2F;...&#x2F;how_to_django&#x2F;lwdj  (master *%) ⤷
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;Run the migrations:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;(dj) ~&#x2F;...&#x2F;how_to_django&#x2F;lwdj  (master *%)
&lt;&#x2F;span&gt;&lt;span&gt;⤷ python single.py migrate
&lt;&#x2F;span&gt;&lt;span&gt;Operations to perform:
&lt;&#x2F;span&gt;&lt;span&gt;  Apply all migrations: admin, auth, contenttypes, lwdj, sessions
&lt;&#x2F;span&gt;&lt;span&gt;Running migrations:
&lt;&#x2F;span&gt;&lt;span&gt;  Applying contenttypes.0001_initial... OK
&lt;&#x2F;span&gt;&lt;span&gt;  Applying auth.0001_initial... OK
&lt;&#x2F;span&gt;&lt;span&gt;  Applying admin.0001_initial... OK
&lt;&#x2F;span&gt;&lt;span&gt;  Applying admin.0002_logentry_remove_auto_add... OK
&lt;&#x2F;span&gt;&lt;span&gt;  Applying contenttypes.0002_remove_content_type_name... OK
&lt;&#x2F;span&gt;&lt;span&gt;  Applying auth.0002_alter_permission_name_max_length... OK
&lt;&#x2F;span&gt;&lt;span&gt;  Applying auth.0003_alter_user_email_max_length... OK
&lt;&#x2F;span&gt;&lt;span&gt;  Applying auth.0004_alter_user_username_opts... OK
&lt;&#x2F;span&gt;&lt;span&gt;  Applying auth.0005_alter_user_last_login_null... OK
&lt;&#x2F;span&gt;&lt;span&gt;  Applying auth.0006_require_contenttypes_0002... OK
&lt;&#x2F;span&gt;&lt;span&gt;  Applying auth.0007_alter_validators_add_error_messages... OK
&lt;&#x2F;span&gt;&lt;span&gt;  Applying auth.0008_alter_user_username_max_length... OK
&lt;&#x2F;span&gt;&lt;span&gt;  Applying lwdj.0001_initial... OK
&lt;&#x2F;span&gt;&lt;span&gt;  Applying sessions.0001_initial... OK
&lt;&#x2F;span&gt;&lt;span&gt;(dj) ~&#x2F;...&#x2F;how_to_django&#x2F;lwdj  (master *%)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;Create a super user and run the server:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;(dj) ~&#x2F;...&#x2F;how_to_django&#x2F;lwdj  (master *%)
&lt;&#x2F;span&gt;&lt;span&gt;⤷ python single.py createsuperuser
&lt;&#x2F;span&gt;&lt;span&gt;Username (leave blank to use &amp;#39;nsukami&amp;#39;):
&lt;&#x2F;span&gt;&lt;span&gt;Email address: nsukami@gmail.com
&lt;&#x2F;span&gt;&lt;span&gt;Password:
&lt;&#x2F;span&gt;&lt;span&gt;Password (again):
&lt;&#x2F;span&gt;&lt;span&gt;Superuser created successfully.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;(dj) ~&#x2F;...&#x2F;how_to_django&#x2F;lwdj  (master *%)
&lt;&#x2F;span&gt;&lt;span&gt;⤷ python single.py runserver
&lt;&#x2F;span&gt;&lt;span&gt;Performing system checks...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;System check identified no issues (0 silenced).
&lt;&#x2F;span&gt;&lt;span&gt;January 12, 2017 - 18:52:57
&lt;&#x2F;span&gt;&lt;span&gt;Django version 1.10.4, using settings None
&lt;&#x2F;span&gt;&lt;span&gt;Starting development server at http:&#x2F;&#x2F;127.0.0.1:8000&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;Quit the server with CONTROL-C.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;so-what-have-we-learned-here&quot;&gt;&lt;strong&gt;So, what have we learned here?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Yes, that is not how you are supposed to use Django. But we were able to learn few things.
&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;projects-and-applications&quot;&gt;&lt;strong&gt;Projects and applications&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Somewhere in the Django documentation related to &lt;a href=&quot;https:&#x2F;&#x2F;docs.djangoproject.com&#x2F;en&#x2F;1.10&#x2F;ref&#x2F;applications&#x2F;#projects-and-applications&quot;&gt;projects and applications&lt;&#x2F;a&gt;, we can read:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;There&#x27;s no restriction that a project package can&#x27;t also be considered an application and have models, etc. (which would require adding it to INSTALLED_APPS).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;We can double check using the &lt;code&gt;tree&lt;&#x2F;code&gt; command:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;(dj) ~&#x2F;...&#x2F;how_to_django&#x2F;lwdj  (master *%)
&lt;&#x2F;span&gt;&lt;span&gt;⤷ tree
&lt;&#x2F;span&gt;&lt;span&gt;.
&lt;&#x2F;span&gt;&lt;span&gt;├── activate -&amp;gt; &#x2F;home&#x2F;nsukami&#x2F;envs&#x2F;dj&#x2F;bin&#x2F;activate
&lt;&#x2F;span&gt;&lt;span&gt;├── db.sqlite3
&lt;&#x2F;span&gt;&lt;span&gt;├── Makefile
&lt;&#x2F;span&gt;&lt;span&gt;├── media
&lt;&#x2F;span&gt;&lt;span&gt;├── migrations
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── 0001_initial.py
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── __init__.py
&lt;&#x2F;span&gt;&lt;span&gt;│   └── __pycache__
&lt;&#x2F;span&gt;&lt;span&gt;│       └── __init__.cpython-36.pyc
&lt;&#x2F;span&gt;&lt;span&gt;├── single.py
&lt;&#x2F;span&gt;&lt;span&gt;├── static
&lt;&#x2F;span&gt;&lt;span&gt;│   └── site.css
&lt;&#x2F;span&gt;&lt;span&gt;├── static_root
&lt;&#x2F;span&gt;&lt;span&gt;└── templates
&lt;&#x2F;span&gt;&lt;span&gt;    └── home.html
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h4 id=&quot;the-django-setup-method&quot;&gt;&lt;strong&gt;The django.setup() method&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Reading The Fabulous &lt;a href=&quot;https:&#x2F;&#x2F;docs.djangoproject.com&#x2F;en&#x2F;dev&#x2F;ref&#x2F;applications&#x2F;#how-applications-are-loaded&quot;&gt;Manual&lt;&#x2F;a&gt;, we learn that, this method configures Django by loading the settings, but also:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;When Django starts, django.setup() is responsible for populating the application registry.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Let&#x27;s start a shell using the command &lt;code&gt;python single.py shell&lt;&#x2F;code&gt;, and let&#x27;s check the application registry:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;django.apps &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;apps
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt; apps.ready
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;True
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt; apps.get_app_configs()
&lt;&#x2F;span&gt;&lt;span&gt;odict_values([&amp;lt;AppConfig: lwdj&amp;gt;, &amp;lt;AdminConfig: admin&amp;gt;, &amp;lt;AuthConfig: auth&amp;gt;, &amp;lt;ContentTypesConfig: contenttypes&amp;gt;, &amp;lt;SessionsConfig: sessions&amp;gt;, &amp;lt;MessagesConfig: messages&amp;gt;, &amp;lt;StaticFilesConfig: staticfiles&amp;gt;, &amp;lt;AppConfig: rest_framework&amp;gt;])
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt; c = apps.get_app_config(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;lwdj&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt; c.module
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;module &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;lwdj&amp;#39; &lt;&#x2F;span&gt;&lt;span&gt;(namespace)&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt; c.path
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;GITHUB&#x2F;how_tos&#x2F;how_to_django&#x2F;lwdj&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt; c.verbose_name
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;Lwdj&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt; c.name
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;lwdj&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt; c.label
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;lwdj&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;m &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;c.models: print(m)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;author
&lt;&#x2F;span&gt;&lt;span&gt;book
&lt;&#x2F;span&gt;&lt;span&gt;(dj) &amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Neat!
&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We also &lt;a href=&quot;https:&#x2F;&#x2F;docs.djangoproject.com&#x2F;en&#x2F;dev&#x2F;ref&#x2F;applications&#x2F;#how-applications-are-loaded&quot;&gt;read&lt;&#x2F;a&gt; that:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;At this stage, your code shouldn&#x27;t import any models!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This is exactly why our models, and everything related to them, do not appear before those 2 lines of code.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;django
&lt;&#x2F;span&gt;&lt;span&gt;django.setup()
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;Doing otherwise, raises the &lt;code&gt;AppRegistryNotReady&lt;&#x2F;code&gt; exception:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;(dj) ~&#x2F;...&#x2F;how_to_django&#x2F;lwdj  (master *%)
&lt;&#x2F;span&gt;&lt;span&gt;⤷ python single.py runserver
&lt;&#x2F;span&gt;&lt;span&gt;Traceback (most recent call last):
&lt;&#x2F;span&gt;&lt;span&gt;  File &amp;quot;single.py&amp;quot;, line 90, in &amp;lt;module&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    class Author(models.Model):
&lt;&#x2F;span&gt;&lt;span&gt;  File &amp;quot;&#x2F;home&#x2F;nsukami&#x2F;envs&#x2F;dj&#x2F;lib&#x2F;python3.6&#x2F;site-packages&#x2F;django&#x2F;db&#x2F;models&#x2F;base.py&amp;quot;, line 105, in __new__
&lt;&#x2F;span&gt;&lt;span&gt;    app_config = apps.get_containing_app_config(module)
&lt;&#x2F;span&gt;&lt;span&gt;  File &amp;quot;&#x2F;home&#x2F;nsukami&#x2F;envs&#x2F;dj&#x2F;lib&#x2F;python3.6&#x2F;site-packages&#x2F;django&#x2F;apps&#x2F;registry.py&amp;quot;, line 237, in get_containing_app_config
&lt;&#x2F;span&gt;&lt;span&gt;    self.check_apps_ready()
&lt;&#x2F;span&gt;&lt;span&gt;  File &amp;quot;&#x2F;home&#x2F;nsukami&#x2F;envs&#x2F;dj&#x2F;lib&#x2F;python3.6&#x2F;site-packages&#x2F;django&#x2F;apps&#x2F;registry.py&amp;quot;, line 124, in check_apps_ready
&lt;&#x2F;span&gt;&lt;span&gt;    raise AppRegistryNotReady(&amp;quot;Apps aren&amp;#39;t loaded yet.&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;django.core.exceptions.AppRegistryNotReady: Apps aren&amp;#39;t loaded yet.
&lt;&#x2F;span&gt;&lt;span&gt;(dj) ~&#x2F;...&#x2F;how_to_django&#x2F;lwdj  (master *%)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h4 id=&quot;installed-applications&quot;&gt;&lt;strong&gt;Installed applications&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;I have not yet fully understood this part. &lt;code&gt;APP_LABEL&lt;&#x2F;code&gt; is actually containing the name of the current directory. By putting &lt;code&gt;APP_LABEL&lt;&#x2F;code&gt; inside &lt;code&gt;INSTALLED_APPS&lt;&#x2F;code&gt;, Django was able to find all the Django models existing inside the current directory:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;BASE_DIR = os.path.dirname(os.path.abspath(__file__))
&lt;&#x2F;span&gt;&lt;span&gt;sys.path[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] = os.path.dirname(BASE_DIR)
&lt;&#x2F;span&gt;&lt;span&gt;APP_LABEL = os.path.basename(BASE_DIR)
&lt;&#x2F;span&gt;&lt;span&gt;{{&amp;lt; &#x2F;highlight &amp;gt;}}
&lt;&#x2F;span&gt;&lt;span&gt;{{&amp;lt; highlight python &amp;gt;}}
&lt;&#x2F;span&gt;&lt;span&gt;    INSTALLED_APPS=[
&lt;&#x2F;span&gt;&lt;span&gt;        APP_LABEL,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.admin&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.auth&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.contenttypes&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.sessions&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.messages&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;django.contrib.staticfiles&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;rest_framework&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        ],
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h4 id=&quot;app-label&quot;&gt;&lt;strong&gt;App label&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;All our models were created outside of a &lt;code&gt;models.py&lt;&#x2F;code&gt; file. They&#x27;re not even in a &lt;em&gt;real&lt;&#x2F;em&gt; Django application. So we were obliged to tell them which application they belongs to. This is done using the &lt;a href=&quot;https:&#x2F;&#x2F;docs.djangoproject.com&#x2F;en&#x2F;1.10&#x2F;ref&#x2F;models&#x2F;options&#x2F;#app-label&quot;&gt;app_label&lt;&#x2F;a&gt; attribute of the internal &lt;code&gt;class Meta&lt;&#x2F;code&gt; of Django models.
{{&amp;lt; highlight python &amp;gt;}}
class Author(models.Model):
name = models.CharField(max_length=200)
class Meta:
app_label = APP_LABEL&lt;&#x2F;p&gt;
&lt;p&gt;class Book(models.Model):
author = models.ForeignKey(Author, related_name=&#x27;books&#x27;)
title = models.CharField(max_length=400)
class Meta:
app_label = APP_LABEL
{{&amp;lt; &#x2F;highlight &amp;gt;}}
&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Really hope you learnt something. Also, I would not be able to write this post, without following the &lt;em&gt;StackTrace&lt;&#x2F;em&gt; leaved by the people who were there before me. A huge thanks to them:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;dotmobo.github.io&#x2F;django-minimaliste.html&quot;&gt;Créer une application django minimaliste&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;blog.fahhem.com&#x2F;2011&#x2F;10&#x2F;django-models-without-apps-or-everything-django-truly-in-a-single-file&#x2F;&quot;&gt;Django Models without Apps OR Everything Django Truly in a Single File&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;zenwalker&#x2F;django-micro&quot;&gt;Django as microframework&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Make</title>
        <published>2016-11-25T00:00:00+00:00</published>
        <updated>2016-11-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/mk/"/>
        <id>https://nskm.xyz/posts/mk/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/mk/">&lt;p&gt;if you have some &lt;strong&gt;complex and esoteric shell commands&lt;&#x2F;strong&gt; that you have to run on a regular basis, it can be convenient to just package them up &lt;em&gt;somewhere&lt;&#x2F;em&gt;, so you don&#x27;t have to &lt;strong&gt;remember them&lt;&#x2F;strong&gt; or &lt;strong&gt;type them out every time&lt;&#x2F;strong&gt;. &lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Why, I don&#x27;t use Makefiles more often? Even though I know I should. One of the reason may be because, as an Emacs user, automating simple tasks is &lt;em&gt;funny&lt;&#x2F;em&gt; using &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;emacs&#x2F;manual&#x2F;html_node&#x2F;elisp&#x2F;&quot;&gt;Emacs Lisp&lt;&#x2F;a&gt;. Following are simple elisp functions I use to compile a C file, nothing extraordinary:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;lisp&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-lisp &quot;&gt;&lt;code class=&quot;language-lisp&quot; data-lang=&quot;lisp&quot;&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;defun &lt;&#x2F;span&gt;&lt;span&gt;my-c-save-compile ()
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Save, and compile c file.&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  (interactive)
&lt;&#x2F;span&gt;&lt;span&gt;  (save-buffer)
&lt;&#x2F;span&gt;&lt;span&gt;  (compile
&lt;&#x2F;span&gt;&lt;span&gt;   (format &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;cc -Wall -Wextra -pedantic -std=c11 -g %s -o .&#x2F;bin&#x2F;%s&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;           (buffer-file-name)
&lt;&#x2F;span&gt;&lt;span&gt;           (file-name-base (buffer-file-name)))))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;defun &lt;&#x2F;span&gt;&lt;span&gt;my-c-run ()
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Run c code.&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  (interactive)
&lt;&#x2F;span&gt;&lt;span&gt;  (compile (format &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;.&#x2F;bin&#x2F;%s&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;                   (file-name-base (buffer-file-name)))))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;Another reason I don&#x27;t use Makefiles more often could be, the &lt;a href=&quot;http:&#x2F;&#x2F;www.tldp.org&#x2F;LDP&#x2F;Bash-Beginners-Guide&#x2F;html&#x2F;Bash-Beginners-Guide.html&quot;&gt;Bourne Again Shell&lt;&#x2F;a&gt;. I find it easier to quickly write shell aliases for repetitive tasks. The following is some aliases I &lt;em&gt;sometimes&lt;&#x2F;em&gt; use whenever I&#x27;m doing &lt;a href=&quot;https:&#x2F;&#x2F;www.djangoproject.com&#x2F;&quot;&gt;Django&lt;&#x2F;a&gt; development:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;#!&#x2F;bin&#x2F;sh
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# my weird aliases
&lt;&#x2F;span&gt;&lt;span&gt;alias djo_runserver=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;python manage.py runserver&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;alias djo_shell=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;python manage.py shell&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;alias djo_shellp=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;python manage.py shell_plus&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;alias djo_make=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;python manage.py makemigrations&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;alias djo_mig=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;python manage.py migrate&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;alias djo_csu=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;python manage.py createsuperuser&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;alias djo_smtpd=&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&amp;quot;python -m smtpd -n -c DebuggingServer localhost:1025&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;Make do have a reputation for being complex. Indeed, it can be very &lt;a href=&quot;http:&#x2F;&#x2F;okmij.org&#x2F;ftp&#x2F;Computation&#x2F;#Makefile-functional&quot;&gt;esoteric&lt;&#x2F;a&gt;. The full &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;make&#x2F;manual&#x2F;make.html&quot;&gt;manual&lt;&#x2F;a&gt; is a 183 pages. Fortunately, you can ignore most of this, Make can be used in a very simple and incredibly useful way. &lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The following, is a Makefile I sometimes use in replacement of the shell aliases above:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;make&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-make &quot;&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Makefile for (the project)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;#
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Nsukami
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# November 2016
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;SHELL := &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&#x2F;bin&#x2F;sh&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;PROJECT := &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;tas&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;PYTHON_BIN := &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#dcdcdc;&quot;&gt;VIRTUAL_ENV&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;&#x2F;bin&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;DEV_SETTINGS = &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#dcdcdc;&quot;&gt;PROJECT&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.settings.dev&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;PROD_SETTINGS = &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#dcdcdc;&quot;&gt;PROJECT&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.settings.prod&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;TEST_SETTINGS = &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#dcdcdc;&quot;&gt;PROJECT&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;.settings.test&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;BASE_DIR = &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#dcdcdc;&quot;&gt;shell dirname &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#dcdcdc;&quot;&gt;realpath &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#dcdcdc;&quot;&gt;lastword &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#dcdcdc;&quot;&gt;MAKEFILE_LIST&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;))))&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;PMP = &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;python manage.py&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# if not on prod server, use dev settings
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;ifneq &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;shell uname -n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;,phobos)
&lt;&#x2F;span&gt;&lt;span&gt;    SETTINGS = &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#dcdcdc;&quot;&gt;DEV_SETTINGS&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;else
&lt;&#x2F;span&gt;&lt;span&gt;    SETTINGS = &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#dcdcdc;&quot;&gt;PROD_SETTINGS&lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#569cd6;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;endif
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# target: all - Default target. Does nothing.
&lt;&#x2F;span&gt;&lt;span&gt;all:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;echo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;Nothing to do by default. Try &amp;#39;make help&amp;#39;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# target: help - Show list of targets + description
&lt;&#x2F;span&gt;&lt;span&gt;help:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span&gt;egrep &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;^# target:&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;Mm&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;akefile
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# target: init - Install that a dev needs to get up and running.
&lt;&#x2F;span&gt;&lt;span&gt;init: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;bootstrap.sh&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    cd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;BASE_DIR&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;) &amp;amp;&amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;sudo .&#x2F;bootstrap.sh
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# target: clean - remove all useless files
&lt;&#x2F;span&gt;&lt;span&gt;clean: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;clean-pyc clean-build&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# target: clean-pyc - remove all auto generated files
&lt;&#x2F;span&gt;&lt;span&gt;clean-pyc:
&lt;&#x2F;span&gt;&lt;span&gt;    find . -name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;*.pyc&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; -exec rm --force {} +
&lt;&#x2F;span&gt;&lt;span&gt;    find . -name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;*.pyo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; -exec rm --force {} +
&lt;&#x2F;span&gt;&lt;span&gt;    find . -name &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;*~&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; -exec rm --force  {} +
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# target: clean-build - remove all auto generated folders
&lt;&#x2F;span&gt;&lt;span&gt;clean-build:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;rm --force --recursive build&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;rm --force --recursive dist&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;rm --force --recursive htmlcov
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;rm --force --recursive .coverage
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;rm --force --recursive &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;.egg-info
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# target: translate - calls the &amp;quot;makemessages&amp;quot; django command
&lt;&#x2F;span&gt;&lt;span&gt;translate:
&lt;&#x2F;span&gt;&lt;span&gt;    cd &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;BASE_DIR&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;) &amp;amp;&amp;amp; $(&lt;&#x2F;span&gt;&lt;span&gt;PMP&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span&gt;makemessages --settings=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;SETTINGS&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt; -a
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# target: test - calls the &amp;quot;test&amp;quot; django command
&lt;&#x2F;span&gt;&lt;span&gt;test:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;PMP&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span&gt;test --settings=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;TEST_SETTINGS&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# target: run - calls the &amp;quot;runserver&amp;quot; django command
&lt;&#x2F;span&gt;&lt;span&gt;run:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;PMP&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span&gt;runserver --settings=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;SETTINGS&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# target: update - install (and update) pip requirements
&lt;&#x2F;span&gt;&lt;span&gt;update:
&lt;&#x2F;span&gt;&lt;span&gt;    pip install -U -r &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;BASE_DIR&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;requirements&#x2F;dev.txt
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# target: collect - calls the &amp;quot;collectstatic&amp;quot; django command
&lt;&#x2F;span&gt;&lt;span&gt;collect:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;PMP&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span&gt;collectstatic --settings=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;SETTINGS&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt; --noinput
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# target: rebuild - rebuild tables from models
&lt;&#x2F;span&gt;&lt;span&gt;rebuild:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;PMP&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span&gt;makemigrations --settings=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;SETTINGS&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;PMP&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span&gt;migrate --settings=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span&gt;SETTINGS&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# target: deploy - let make take care of deployment
&lt;&#x2F;span&gt;&lt;span&gt;deploy:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Should I call fabric here?
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;.ONESHELL:
&lt;&#x2F;span&gt;&lt;span&gt;.PHONY: &lt;&#x2F;span&gt;&lt;span style=&quot;background-color:#282828;color:#d69d85;&quot;&gt;all help translate test clean update collect rebuild run clean-pyc clean-build clean init&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;Finally, the other reason, and probably the main reason I don&#x27;t use Makefiles more often, it&#x27;s because of &lt;a href=&quot;http:&#x2F;&#x2F;www.fabfile.org&#x2F;&quot;&gt;Fabric&lt;&#x2F;a&gt;. Following is a fabfile more or less doing the same thing as the Makefile above:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env python
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# -*- coding: utf-8 -*- #
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&amp;quot;&amp;quot;&amp;quot; fabric commands &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;fabric.api &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;env, sudo, cd, local, task, run
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;fabric.contrib.project &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;project
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;os
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# Local path configuration (can be absolute or relative to fabfile)
&lt;&#x2F;span&gt;&lt;span&gt;env.hosts = [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;localhost&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;env.use_ssh_config = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;True
&lt;&#x2F;span&gt;&lt;span&gt;env.ssh_config_path = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&#x2F;home&#x2F;nsukami&#x2F;.ssh&#x2F;config&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;env.owner = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;nsukami&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;PROJECT = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;tas&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;DEV_SETTINGS = PROJECT + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;.settings.dev&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;PROD_SETTINGS = PROJECT + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;.settings.prod&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;TEST_SETTINGS = PROJECT + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;.settings.test&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;BASE_DIR = os.path.dirname(os.path.abspath(__file__))
&lt;&#x2F;span&gt;&lt;span&gt;PMP = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;python manage.py &amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;uname():
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&amp;quot;&amp;quot;&amp;quot; Prints information about the host. &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    local(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;uname -n&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;uname() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;is not &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;phobos&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    SETTINGS = DEV_SETTINGS
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    SETTINGS = PROD_SETTINGS
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@task
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;init():
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;init - Install that a dev needs to get up and running.&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;with &lt;&#x2F;span&gt;&lt;span&gt;cd(BASE_DIR):
&lt;&#x2F;span&gt;&lt;span&gt;        sudo(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;.&#x2F;bootstrap.sh&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@task
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;clean():
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;clean - remove all useless files&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    clean_pyc()
&lt;&#x2F;span&gt;&lt;span&gt;    clean_build()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;clean_pyc():
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;# clean-pyc - remove all auto generated files&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    local(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;find . -name &amp;#39;*.pyc&amp;#39; -exec rm --force &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt; +&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    local(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;find . -name &amp;#39;*.pyo&amp;#39; -exec rm --force &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt; +&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    local(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;find . -name &amp;#39;*~&amp;#39; -exec rm --force  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt; +&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;clean_build():
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;clean-build - remove all auto generated folders&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    local(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;rm --force --recursive build&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    local(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;rm --force --recursive dist&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    local(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;rm --force --recursive htmlcov&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    local(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;rm --force --recursive .coverage&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    local(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;rm --force --recursive *.egg-info&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@task
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;translate():
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;translate - calls the &amp;#39;makemessages&amp;#39; django command&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;with &lt;&#x2F;span&gt;&lt;span&gt;cd(BASE_DIR):
&lt;&#x2F;span&gt;&lt;span&gt;        cmd = PMP + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;makemessages --settings=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt; -a&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.format(SETTINGS)
&lt;&#x2F;span&gt;&lt;span&gt;        local(cmd)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@task
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;test():
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;test - calls the &amp;#39;test&amp;#39; django command&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    cmd = PMP + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;test --settings=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.format(SETTINGS)
&lt;&#x2F;span&gt;&lt;span&gt;    local(cmd)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@task
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;runserver():
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;run - calls the &amp;#39;runserver&amp;#39; django command&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    cmd = PMP + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;runserver --settings=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.format(SETTINGS)
&lt;&#x2F;span&gt;&lt;span&gt;    local(cmd)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;@task
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span&gt;update():
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;update - install (and update) pip requirements&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    cmd = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;pip install -U -r &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&#x2F;requirements&#x2F;dev.txt&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.format(BASE_DIR)
&lt;&#x2F;span&gt;&lt;span&gt;    local(cmd)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;We see that Fabric &lt;em&gt;can&lt;&#x2F;em&gt; be used as a build tool even though it isn&#x27;t one. It is easy to read and write, especially for a Python developer. The drawback may be, it does require Python to run. &lt;em&gt;Seriously, who cares?&lt;&#x2F;em&gt;
&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;New year resolution: &lt;strong&gt;using Makefiles more often.&lt;&#x2F;strong&gt;
&lt;br&gt;&lt;br&gt;
More on the topic:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;make&#x2F;manual&#x2F;make.html&quot;&gt;Make&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=5276339&quot;&gt;Make alternatives&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;List_of_build_automation_software&quot;&gt;List of build automation software&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How to create processes</title>
        <published>2016-08-22T03:40:17+00:00</published>
        <updated>2016-08-22T03:40:17+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/process-creation/"/>
        <id>https://nskm.xyz/posts/process-creation/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/process-creation/">&lt;p&gt;We&#x27;ve seen &lt;a href=&quot;&#x2F;on-processes.md&quot;&gt;processes&lt;&#x2F;a&gt;, We&#x27;ve said lots of things about processes, but we did not talk about process creation. Let&#x27;s see how to create a process in C, in &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;&quot;&gt;Golang&lt;&#x2F;a&gt;, and in &lt;a href=&quot;https:&#x2F;&#x2F;www.rust-lang.org&#x2F;en-US&#x2F;&quot;&gt;Rustlang&lt;&#x2F;a&gt; &lt;em&gt;&lt;strong&gt;Disclaimer:&lt;&#x2F;strong&gt; I&#x27;m not doing a comparison to find out which one is better than the other. I just want to explore how the same task can be done using different approaches.&lt;br&gt;&lt;br&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fork-and-exec&quot;&gt;&lt;strong&gt;Fork and Exec:&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;UNIX processes are created using the fork() &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;System_call&quot;&gt;system call&lt;&#x2F;a&gt;. Fork is the primary method of process creation on Unix-like operating systems.  Fork is the system call that the parent process uses to &quot;divide&quot; itself, to &quot;fork&quot; into two identical processes. The child process will be the exact copy of the parent except for the return value.&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Exec_(system_call)&quot;&gt;exec()&lt;&#x2F;a&gt; system call and its family of functions are almost always used with fork(). The exec() syscall and the like overwrite the current [stackframe]({{&amp;lt; ref on-processes &amp;gt;}})with the name of the application passed to it.&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;c&quot;&gt;&lt;strong&gt;C:&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;In C, there is nothing special to do, contrary to Golang and Rustlang. You just really call fork(), then exec(), simple and direct. The following, is an example written in C:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;sys&#x2F;types.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;unistd.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;sys&#x2F;wait.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;string.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;fork_and_execute();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main() {
&lt;&#x2F;span&gt;&lt;span&gt;  fork_and_execute();
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;fork_and_execute() {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; pid, status;
&lt;&#x2F;span&gt;&lt;span&gt;  pid = fork();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; if pid equals 0,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;(pid == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;){
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; we&amp;#39;re dealing with the child process
&lt;&#x2F;span&gt;&lt;span&gt;    printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;I am the child process, my pid is &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, getpid());
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; the program we want to execute
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;cmd[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;] = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;ls&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-a&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-l&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-h&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; execvp will search for ls on $PATH
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(execvp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;cmd, cmd) &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;){
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; catch any error that may occur during execution
&lt;&#x2F;span&gt;&lt;span&gt;      printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;*** ERROR: exec failed&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;      perror(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;cmd);
&lt;&#x2F;span&gt;&lt;span&gt;      exit(EXIT_FAILURE);
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; returned pid is -1, fork operation failed
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;(pid &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;){
&lt;&#x2F;span&gt;&lt;span&gt;    printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;*** ERROR: forking child process failed&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    perror(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;fork&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    exit(EXIT_FAILURE);
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; The wait system-call blocks the parent process
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; and waits for the child-process to end.
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;while &lt;&#x2F;span&gt;&lt;span&gt;(wait(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;status) != pid){}
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h4 id=&quot;go&quot;&gt;&lt;strong&gt;Go:&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;In Go, it is recommended to use the &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;pkg&#x2F;os&#x2F;exec&#x2F;&quot;&gt;exec&lt;&#x2F;a&gt; package. It runs external commands, and wraps &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;pkg&#x2F;os&#x2F;#StartProcess&quot;&gt;os.StartProcess&lt;&#x2F;a&gt; function for you. Following, is the previous example, this time written in Golang:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-go &quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;package &lt;&#x2F;span&gt;&lt;span&gt;main
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;syscall&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;os&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;os&#x2F;exec&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;func &lt;&#x2F;span&gt;&lt;span&gt;main() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; check if ls command exists in the PATH
&lt;&#x2F;span&gt;&lt;span&gt;    binary, lookErr := exec.LookPath(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;ls&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;lookErr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;!= nil &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        panic(lookErr)
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; the program we want to execute
&lt;&#x2F;span&gt;&lt;span&gt;    args := []string{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;ls&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-a&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-l&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-h&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; fork new process and execute our program
&lt;&#x2F;span&gt;&lt;span&gt;    execErr := syscall.Exec(binary, args, os.Environ())
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F; catch error if any
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;execErr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;!= nil &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        panic(execErr)
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h4 id=&quot;rust&quot;&gt;&lt;strong&gt;Rust:&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;In Rust, we have &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;process&#x2F;struct.Command.html&quot;&gt;std::process::Command&lt;&#x2F;a&gt;. It is is a type that acts as a process builder and provides fine-grained control over how the new process should be spawned. If we browse the &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;src&#x2F;std&#x2F;process.rs.html#521&quot;&gt;source code&lt;&#x2F;a&gt;, we can read beginning line 521:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Constructs a new &lt;code&gt;Command&lt;&#x2F;code&gt; for launching the program at&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;path &lt;code&gt;program&lt;&#x2F;code&gt;, with the following default configuration:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;No arguments to the program&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Inherit the current process&#x27;s environment&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Inherit the current process&#x27;s working directory&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Inherit stdin&#x2F;stdout&#x2F;stderr for &lt;code&gt;spawn&lt;&#x2F;code&gt; or &lt;code&gt;status&lt;&#x2F;code&gt;, but create pipes for &lt;code&gt;output&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;br&gt;
&lt;p&gt;Basically, it behave a little bit like a call to fork(), followed by a call to exec(). Let&#x27;s rewrite the previous example in Rust:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::process::Command;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span&gt;main() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; output = Command::new(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;ls&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;                     .arg(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-a&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;                     .arg(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-l&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;                     .arg(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-h&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;                     .output()
&lt;&#x2F;span&gt;&lt;span&gt;                     .expect(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;ls command failed to start&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    println!(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;stdout: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, String::from_utf8_lossy(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;output.stdout));
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;process&#x2F;struct.Command.html#method.output&quot;&gt;output&lt;&#x2F;a&gt; function executes the command as a child process, waiting for it to finish and collecting all of its output. By default, stdin, stdout and stderr are captured (and used to provide the resulting output).&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;option&#x2F;enum.Option.html#method.expect&quot;&gt;expect&lt;&#x2F;a&gt; function is used for quick and dirty error handling.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h3 id=&quot;strace-trace-system-calls-and-signals&quot;&gt;&lt;strong&gt;Strace, trace system calls and signals:&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Somewhere in the strace&#x27;s manual page, we can read:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Trace child processes as they are created by currently traced processes as a result of the fork(2), vfork(2) and clone(2) system calls.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;If everything went normally during the execution of our scripts, we should see, in the strace&#x27;s output, lots of system calls, the most important ones being a call to &lt;strong&gt;clone()&lt;&#x2F;strong&gt;, followed by a call to &lt;strong&gt;exec()&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;4714  clone(child_stack=0, flags=CLONE_CHILD_CLEARTID&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt;CLONE_CHILD_SETTID&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;|&lt;&#x2F;span&gt;&lt;span&gt;SIGCHLD, child_tidptr=0x7fac5d28da90) = 4715
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;7564  execve(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&#x2F;bin&#x2F;ls&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;ls&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-a&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-l&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-h&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; 74 vars &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;] &lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;unfinished ...&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;fork() was the original UNIX system call. Only used to create new processes, not threads. Also, it is portable.&lt;&#x2F;p&gt;
&lt;p&gt;clone() is a new, versatile system call which can be used to create, depending on the passed option, a UNIX process, or a POSIX thread, or something in between, or something completely different. I invite you to &lt;a href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man2&#x2F;clone.2.html&quot;&gt;Read The Fabulous Manual&lt;&#x2F;a&gt; about clone().&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I don&#x27;t really know if there is something else you can read to learn more on this topic:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man2&#x2F;fork.2.html&quot;&gt;Fork&lt;&#x2F;a&gt; manual page.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man3&#x2F;exec.3.html&quot;&gt;Exec&lt;&#x2F;a&gt; manual page.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man2&#x2F;clone.2.html&quot;&gt;Clone&lt;&#x2F;a&gt; manual page.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man1&#x2F;strace.1.html&quot;&gt;Strace&lt;&#x2F;a&gt; manual page.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Processes</title>
        <published>2016-08-09T03:40:17+00:00</published>
        <updated>2016-08-09T03:40:17+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/processes-introduction/"/>
        <id>https://nskm.xyz/posts/processes-introduction/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/processes-introduction/">&lt;p&gt;As a Debian user, I often want to see the active processes, sometimes, I want to kill them. I know how to launch a new process, inside my Python scripts. But what is a process?&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;p&gt;A process is the execution context of a running program. When an executable program is read into memory by the kernel and executed, it becomes a process. Processes are dynamic entities, they are constantly changing as their machine code instructions are executed by the CPU.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;p&gt;With the exception of the &lt;code&gt;init process&lt;&#x2F;code&gt;, every process is the child of another process. And every process has the potential to be the parent of another process. The following is a small C program that will print the current process ID and the corresponding parent process ID:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;unistd.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main (){
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char&lt;&#x2F;span&gt;&lt;span&gt; ch;
&lt;&#x2F;span&gt;&lt;span&gt;  printf (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;The process ID is &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;) getpid ());
&lt;&#x2F;span&gt;&lt;span&gt;  printf (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;The parent process ID is &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b4cea8;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;) getppid ());
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;while &lt;&#x2F;span&gt;&lt;span&gt;( ch != &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\r&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39; &lt;&#x2F;span&gt;&lt;span&gt;&amp;amp;&amp;amp; ch != &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39; &lt;&#x2F;span&gt;&lt;span&gt;){
&lt;&#x2F;span&gt;&lt;span&gt;    ch = getchar();
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After execution, you should see something like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;~
&lt;&#x2F;span&gt;&lt;span&gt;+-&amp;gt; .&#x2F;bin&#x2F;ex1
&lt;&#x2F;span&gt;&lt;span&gt;The process ID is 11147
&lt;&#x2F;span&gt;&lt;span&gt;The parent process ID is 9552
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a name=&quot;vas&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;virtual-address-space&quot;&gt;&lt;strong&gt;Virtual address space?&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;A virtual address space, &lt;code&gt;VAS&lt;&#x2F;code&gt;, is the set of ranges of virtual addresses available to a process. The virtual address space is what a process sees when it executes. A process works with and only sees VAS. The operating system handles mapping VAS to real storage so that this is invisible to the running program.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;p&gt;We need VAS to prevent process A and process B from writing&#x2F;reading in the same memory addresses. VAS is a way to achieve &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Process_isolation&quot;&gt;process isolation&lt;&#x2F;a&gt;. With VAS, several programs could write to memory location at the same address without stepping over each others results.&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;center&gt;

&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;nskm.xyz&amp;#x2F;processed_images&amp;#x2F;vas-schema.9c317ee408a2f21e.png&quot; &#x2F;&gt;
&lt;&#x2F;center&gt;
&lt;p&gt;&lt;em&gt;Image from &lt;a href=&quot;http:&#x2F;&#x2F;www.tenouk.com&#x2F;ModuleW_files&#x2F;ccompilerlinker007.png&quot;&gt;tenouk.com&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;br&gt;
&lt;h3 id=&quot;what-s-inside-vas&quot;&gt;&lt;strong&gt;What&#x27;s inside VAS?&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;VAS&lt;&#x2F;code&gt;, is the set of ranges of virtual addresses available to a process, so what is inside a VAS? A typical memory representation of process consists of following sections:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stack:&lt;&#x2F;strong&gt;&lt;br&gt;
VAS section that is used for several related purposes, the main one being to keep track of the point to which each active subroutine should return control when it finishes executing. The return address is pushed onto the stack by the caller. When it finishes, the called subroutine, pops the return address off the stack and transfers control to that address. &lt;br&gt;&lt;br&gt;That section also stores temporary variables created by each function inside the program. The stack is a LIFO data structure, managed and optimized by the CPU quite closely. Every time a function declares a new variable, it is &quot;pushed&quot; onto the stack, you don&#x27;t have to allocate the needed memory by hand. Then every time a function exits, all of the variables pushed onto the stack by that function, are freed for you. Once a stack variable is freed, that region of memory becomes available for other stack variables.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Heap:&lt;&#x2F;strong&gt;&lt;br&gt;
VAS section where dynamic memory allocation usually takes place. Unlike the Stack, this part of the VAS is not managed automatically for you, and is not as tightly managed by the CPU. You are in charge of allocating memory on the heap. You are also responsible for deallocating that memory once you don&#x27;t need it any more. If you fail to do this, your program will have what is known as a memory leak.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Initialized Data Segment:&lt;&#x2F;strong&gt;&lt;br&gt;
Or simply, Data Segment. VAS section, which contains the global and static variables that are initialized by the programmer. The size of this segment is determined by the size of the values in the program&#x27;s source code, and does not change at run time.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Uninitialized (bss) Data Segment:&lt;&#x2F;strong&gt; &lt;br&gt;
VAS section that contains all global and static variables that are initialized to zero or do not have explicit initialization in the programer&#x27;s source code.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Text (code) Segment:&lt;&#x2F;strong&gt;&lt;br&gt;
VAS section that contains machine instructions of the program. Those machine instructions can be thought of as the text of a novel: It tells the story of what the program does.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;br&gt;
&lt;h3 id=&quot;how-to-do-some-introspection&quot;&gt;&lt;strong&gt;How to do some introspection?&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;How do we learn about the memory layout of a running process? How do we look at how program are laid out in memory?&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Directly from &#x2F;proc&#x2F;PID&#x2F;maps:&lt;br&gt;&lt;&#x2F;strong&gt;
You can directly ask to the process information pseudo-filesystem: &lt;a href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man5&#x2F;proc.5.html&quot;&gt;proc&lt;&#x2F;a&gt;. Let&#x27;s see the output of &lt;code&gt;cat &#x2F;proc&#x2F;6026&#x2F;maps&lt;&#x2F;code&gt;. Here &lt;code&gt;6026&lt;&#x2F;code&gt; is the PID of a running process on my Debian:&lt;br&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;00400000-00401000 r-xp 00000000 08:05 3181468            &#x2F;home&#x2F;nsukami&#x2F;bin&#x2F;how_to_vms
&lt;&#x2F;span&gt;&lt;span&gt;00600000-00601000 rw-p 00000000 08:05 3181468            &#x2F;home&#x2F;nsukami&#x2F;bin&#x2F;how_to_vms
&lt;&#x2F;span&gt;&lt;span&gt;01698000-016b9000 rw-p 00000000 00:00 0                  [heap]
&lt;&#x2F;span&gt;&lt;span&gt;7f747118a000-7f747132c000 r-xp 00000000 08:01 131521     &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;libc-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;7f747132c000-7f747152b000 ---p 001a2000 08:01 131521     &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;libc-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;7f747152b000-7f747152f000 r--p 001a1000 08:01 131521     &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;libc-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;7f747152f000-7f7471531000 rw-p 001a5000 08:01 131521     &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;libc-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;7f7471531000-7f7471535000 rw-p 00000000 00:00 0
&lt;&#x2F;span&gt;&lt;span&gt;7f7471535000-7f7471555000 r-xp 00000000 08:01 130924     &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;ld-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;7f7471734000-7f7471737000 rw-p 00000000 00:00 0
&lt;&#x2F;span&gt;&lt;span&gt;7f7471752000-7f7471755000 rw-p 00000000 00:00 0
&lt;&#x2F;span&gt;&lt;span&gt;7f7471755000-7f7471756000 r--p 00020000 08:01 130924     &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;ld-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;7f7471756000-7f7471757000 rw-p 00021000 08:01 130924     &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;ld-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;7f7471757000-7f7471758000 rw-p 00000000 00:00 0
&lt;&#x2F;span&gt;&lt;span&gt;7ffc4d89b000-7ffc4d8bc000 rw-p 00000000 00:00 0          [stack]
&lt;&#x2F;span&gt;&lt;span&gt;7ffc4d99b000-7ffc4d99d000 r-xp 00000000 00:00 0          [vdso]
&lt;&#x2F;span&gt;&lt;span&gt;7ffc4d99d000-7ffc4d99f000 r--p 00000000 00:00 0          [vvar]
&lt;&#x2F;span&gt;&lt;span&gt;ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0  [vsyscall]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
The Heap segment and the Stack segment are labelled, easy. The addresses are displayed from the lowest `00400000`, to the highest `ffffffffff601000`. The first segment, `00400000-00401000`, is read-only and executable, so, this is the Code segment. We know that between the Code segment, and the Heap segment, there is the Data segment. If you don&#x27;t want to browse the `&#x2F;proc` directory, there is also the [pmap](http:&#x2F;&#x2F;linux.die.net&#x2F;man&#x2F;1&#x2F;pmap) command you can use to report the memory map of a process.
&lt;br&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;Using the GNU debugger:&lt;&#x2F;strong&gt;
GDB, the &lt;em&gt;awesome&lt;&#x2F;em&gt; &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;gdb&#x2F;&quot;&gt;GNU Project debugger&lt;&#x2F;a&gt;, allows you, among others things, to see what is going on &lt;code&gt;inside&lt;&#x2F;code&gt; a running process. For example, from the gdb prompt, you can type &lt;code&gt;info proc mappings&lt;&#x2F;code&gt; to see the current address mapping:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;process 8460
&lt;&#x2F;span&gt;&lt;span&gt;Mapped address spaces:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        Start Addr           End Addr     Size   Offset objfile
&lt;&#x2F;span&gt;&lt;span&gt;          0x400000           0x401000   0x1000      0x0 &#x2F;home&#x2F;nsukami&#x2F;bin&#x2F;how_to_vms
&lt;&#x2F;span&gt;&lt;span&gt;          0x600000           0x601000   0x1000      0x0 &#x2F;home&#x2F;nsukami&#x2F;bin&#x2F;how_to_vms
&lt;&#x2F;span&gt;&lt;span&gt;          0x601000           0x622000  0x21000      0x0 [heap]
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffff7a31000     0x7ffff7bd3000 0x1a2000      0x0 &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;libc-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffff7bd3000     0x7ffff7dd2000 0x1ff000 0x1a2000 &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;libc-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffff7dd2000     0x7ffff7dd6000   0x4000 0x1a1000 &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;libc-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffff7dd6000     0x7ffff7dd8000   0x2000 0x1a5000 &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;libc-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffff7dd8000     0x7ffff7ddc000   0x4000      0x0
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffff7ddc000     0x7ffff7dfc000  0x20000      0x0 &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;ld-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffff7fd7000     0x7ffff7fda000   0x3000      0x0
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffff7ff5000     0x7ffff7ff8000   0x3000      0x0
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffff7ff8000     0x7ffff7ffa000   0x2000      0x0 [vdso]
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffff7ffa000     0x7ffff7ffc000   0x2000      0x0 [vvar]
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffff7ffc000     0x7ffff7ffd000   0x1000  0x20000 &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;ld-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffff7ffd000     0x7ffff7ffe000   0x1000  0x21000 &#x2F;lib&#x2F;x86_64-linux-gnu&#x2F;ld-2.19.so
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffff7ffe000     0x7ffff7fff000   0x1000      0x0
&lt;&#x2F;span&gt;&lt;span&gt;    0x7ffffffde000     0x7ffffffff000  0x21000      0x0 [stack]
&lt;&#x2F;span&gt;&lt;span&gt;0xffffffffff600000 0xffffffffff601000   0x1000      0x0 [vsyscall]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;And there is more to explore:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;(gdb) help info proc
&lt;&#x2F;span&gt;&lt;span&gt;Show &#x2F;proc process information about any running process.
&lt;&#x2F;span&gt;&lt;span&gt;Specify any process id, or use the program being debugged by default.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;List of info proc subcommands:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;info proc all -- List all available &#x2F;proc info
&lt;&#x2F;span&gt;&lt;span&gt;info proc cmdline -- List command line arguments of the process
&lt;&#x2F;span&gt;&lt;span&gt;info proc cwd -- List current working directory of the process
&lt;&#x2F;span&gt;&lt;span&gt;info proc exe -- List absolute filename for executable of the process
&lt;&#x2F;span&gt;&lt;span&gt;info proc mappings -- List of mapped memory regions
&lt;&#x2F;span&gt;&lt;span&gt;info proc stat -- List process info from &#x2F;proc&#x2F;PID&#x2F;stat
&lt;&#x2F;span&gt;&lt;span&gt;info proc status -- List process info from &#x2F;proc&#x2F;PID&#x2F;status
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Type &amp;quot;help info proc&amp;quot; followed by info proc subcommand name for full documentation.
&lt;&#x2F;span&gt;&lt;span&gt;Type &amp;quot;apropos word&amp;quot; to search for commands related to &amp;quot;word&amp;quot;.
&lt;&#x2F;span&gt;&lt;span&gt;Command name abbreviations are allowed if unambiguous.
&lt;&#x2F;span&gt;&lt;span&gt;(gdb)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;h3 id=&quot;how-to-create-a-process&quot;&gt;&lt;strong&gt;How to create a process?&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;1.&lt;strong&gt;fork():&lt;&#x2F;strong&gt;
The fork() system call is used to create processes. It takes no arguments and returns a process ID. The purpose of fork() is to create a new process, which becomes the child process of the caller:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdio.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;sys&#x2F;types.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;unistd.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;stdlib.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;sys&#x2F;wait.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;lt;string.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;execute();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span&gt;main() {
&lt;&#x2F;span&gt;&lt;span&gt;  execute();
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span&gt;execute() {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; pid, status;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt;((pid = fork()) == &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;){
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;char *&lt;&#x2F;span&gt;&lt;span&gt;cmd[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;] = {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;ls&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-a&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-l&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;-h&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(execvp(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;cmd, cmd) &amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;){
&lt;&#x2F;span&gt;&lt;span&gt;      printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;*** ERROR: exec failed&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;      perror(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;cmd);
&lt;&#x2F;span&gt;&lt;span&gt;      exit(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    printf(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;*** ERROR: forking child process failed&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    perror(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;quot;fork&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    exit(EXIT_FAILURE);
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;&#x2F;&#x2F;The parent executes the wait.
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;while &lt;&#x2F;span&gt;&lt;span&gt;(wait(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;status) != pid){}
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I really would like to write more on this topic. Maybe in another post, otherwise the article will be too long, &lt;em&gt;and I have the dishes to do&lt;&#x2F;em&gt;. At least, we&#x27;ve seen that there is an interesting amount of informations behind what is called a process.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;i-hope-you-ve-learned-something-and-if-you-want-to-know-more&quot;&gt;I hope you&#x27;ve learned something, and if you want to know more:&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.tldp.org&#x2F;LDP&#x2F;tlk&#x2F;kernel&#x2F;processes.html&quot;&gt;Processes&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;Documentation&#x2F;filesystems&#x2F;proc.txt&quot;&gt;Proc&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man5&#x2F;proc.5.html&quot;&gt;Proc man pages&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;lwn.net&#x2F;Articles&#x2F;446528&#x2F;&quot;&gt;The &quot;vsyscall&quot; and &quot;vDSO&quot; segments&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;gdb&#x2F;&quot;&gt;GDB&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;turnoff.us&#x2F;geek&#x2F;the-jealous-process&#x2F;&quot;&gt;The jealous process&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Network namespaces</title>
        <published>2016-07-08T00:00:00+00:00</published>
        <updated>2016-07-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/onn/"/>
        <id>https://nskm.xyz/posts/onn/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/onn/">&lt;p&gt;I use LXC containers mainly as isolated environments when I&#x27;m writing code, but also when I just want to try the last version of a package without being obliged to break something on my current configuration. This is the first part of a serie about LXC containers. In this post, I&#x27;ll share with you what I&#x27;ve learned about network namespaces. Everything here will be done under Debian Jessie, as root, I&#x27;m using Python 3.5 and I&#x27;ve pip installed pyroute2.
&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To keep the schemas as simple as possible, I won&#x27;t mention the interface &lt;code&gt;lo&lt;&#x2F;code&gt; actually available inside the &lt;code&gt;root namespace&lt;&#x2F;code&gt;. The &lt;code&gt;root namespace&lt;&#x2F;code&gt; is the namespace available to you after a fresh boot of your Operating System. This is a small schema of my configuration showing you where we&#x27;ll start: &lt;img src=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;onn&#x2F;%7Bfilename%7D&#x2F;images&#x2F;root_ns.png&quot; alt=&quot;Root namespace&quot; &#x2F;&gt;
&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;What we will do:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;onn&#x2F;#namespace-creation&quot;&gt;Create a namespace&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;onn&#x2F;#veth-pair-creation&quot;&gt;Create a virtual ethernet device pair&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;onn&#x2F;#assign-on-side-to-namespace&quot;&gt;Assign one side of the veth pair to the namespace&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;onn&#x2F;#ip-addresses&quot;&gt;Assign IP addresses to each side of the veth pair&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;onn&#x2F;#default-route-for-namespace&quot;&gt;Set the default route for our namespace&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;onn&#x2F;#attach-veth-to-bridge&quot;&gt;Attach the other side of the veth pair to a bridge&lt;&#x2F;a&gt;.
&lt;br&gt;&lt;br&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h4 id=&quot;network-namespaces&quot;&gt;Network namespaces&lt;&#x2F;h4&gt;
&lt;p&gt;A &lt;strong&gt;namespace&lt;&#x2F;strong&gt; is a way of scoping a particular set of identifiers. You can use the same identifier multiple times in different namespaces. Most importantly, you can also restrict an identifier set visible to particular processes.
&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Fact: the set of network interfaces and routing tables are shared across your entire Operating System. &lt;a href=&quot;https:&#x2F;&#x2F;lwn.net&#x2F;Articles&#x2F;580893&#x2F;&quot;&gt;Network namespaces&lt;&#x2F;a&gt; change that fundamental assumption. With network namespaces, you can have different and separate instances of network interfaces and routing tables that operate independent of each other. Let&#x27;s see how it works, using the Python package &lt;a href=&quot;https:&#x2F;&#x2F;pypi.python.org&#x2F;pypi&#x2F;pyroute2&quot;&gt;Pyroute2&lt;&#x2F;a&gt;:
&lt;a name=&quot;namespace-creation&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;pyroute2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;IPDB, IPRoute, NetNS, netns, NSPopen
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;subprocess &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9b9b9b;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;Popen, PIPE
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; ipdb_namespace1 = IPDB(nl=NetNS(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;namespace1&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; nsp = NSPopen(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;namespace1&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ip&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;addr&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;], stdout=PIPE)
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;l &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;nsp.communicate()[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].split(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e3bbab;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...   &lt;&#x2F;span&gt;&lt;span&gt;print(l)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;1: lo: &amp;lt;LOOPBACK&amp;gt; mtu 65536 qdisc noop state DOWN group default &amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;    link&#x2F;loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;We&#x27;ve just created a network namespace named &lt;code&gt;namespace1&lt;&#x2F;code&gt;. The &lt;code&gt;ip addr&lt;&#x2F;code&gt; command launched inside the namespace &lt;code&gt;namespace1&lt;&#x2F;code&gt; tells us that there is only one interface, &lt;code&gt;lo&lt;&#x2F;code&gt;.
&lt;img src=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;onn&#x2F;%7Bfilename%7D&#x2F;images&#x2F;ns_created.png&quot; alt=&quot;Namespace1 created&quot; &#x2F;&gt;
&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now, we need a way to link our newly created namespace, to the &lt;code&gt;root namespace&lt;&#x2F;code&gt;. To do that, virtual ethernet devices, &lt;code&gt;veth pair&lt;&#x2F;code&gt;, need to be created and configured. A &lt;code&gt;veth pair&lt;&#x2F;code&gt; works like a patch cable, connecting two sides. It consists of two virtual interfaces, one of them is assigned to the root network namespace, while the other lives within the network namespace, &lt;code&gt;namespace1&lt;&#x2F;code&gt;:
&lt;a name=&quot;veth-pair-creation&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; ipdb_root = IPDB() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#608b4e;&quot;&gt;# root namespace
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; ipdb_root.create(ifname=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;v01&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, kind=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;veth&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, peer=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;vp01&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;).commit()
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;linkmode&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;broadcast&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ff:ff:ff:ff:ff:ff&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;num_rx_queues&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;qdisc&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;noop&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;txqlen&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ipaddr&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;group&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;flags&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;4098&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;neighbours&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;mtu&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1500&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;promiscuity&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;vlans&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;address&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ca:a0:d7:39:57:22&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ipdb_scope&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;system&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;kind&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;veth&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ipdb_priority&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ifi_type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;family&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;carrier&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ports&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;peer&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;vp01&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;num_tx_queues&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;index&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ifname&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;v01&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;carrier_changes&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;operstate&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;DOWN&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;onn&#x2F;%7Bfilename%7D&#x2F;images&#x2F;veth_created.png&quot; alt=&quot;Veth pair device created&quot; &#x2F;&gt;
&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Veth pair device created. Both sides of the veth pair device are actually in the &lt;code&gt;root namespace&lt;&#x2F;code&gt;. To link the &lt;code&gt;root namespace&lt;&#x2F;code&gt; to our newly created namespace &lt;code&gt;namespace1&lt;&#x2F;code&gt;, one side of the veth pair device, the peer, should be assigned to &lt;code&gt;namespace1&lt;&#x2F;code&gt;:
&lt;a name=&quot;assign-on-side-to-namespace&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;with &lt;&#x2F;span&gt;&lt;span&gt;ipdb_root.interfaces.vp01 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;v:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...   &lt;&#x2F;span&gt;&lt;span&gt;v.net_ns_fd = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;namespace1&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;onn&#x2F;%7Bfilename%7D&#x2F;images&#x2F;veth_peer_moved.png&quot; alt=&quot;Veth peer moved&quot; &#x2F;&gt;
&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now, let&#x27;s give IP addresses to all of our interfaces, and set everybody up:
&lt;a name=&quot;ip-addresses&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;with &lt;&#x2F;span&gt;&lt;span&gt;ipdb_root.interfaces.v01 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;veth:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...     &lt;&#x2F;span&gt;&lt;span&gt;veth.add_ip(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;192.168.1.36&#x2F;24&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...     &lt;&#x2F;span&gt;&lt;span&gt;veth.up()
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;kind&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;veth&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;promiscuity&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;group&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ipdb_scope&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;system&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;peer&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;vp01&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;linkmode&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ipdb_priority&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;carrier_changes&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;address&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;f2:2d:aa:9d:16:da&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;mtu&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1500&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;carrier&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ifname&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;v01&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;num_tx_queues&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;index&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ifi_type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ports&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;vlans&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ipaddr&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;qdisc&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;noop&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;neighbours&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;txqlen&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;broadcast&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ff:ff:ff:ff:ff:ff&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;operstate&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;DOWN&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;num_rx_queues&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;flags&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;4098&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;family&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;with &lt;&#x2F;span&gt;&lt;span&gt;ipdb_namespace1.interfaces.vp01 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;veth:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...     &lt;&#x2F;span&gt;&lt;span&gt;veth.add_ip(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;192.168.1.37&#x2F;24&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...     &lt;&#x2F;span&gt;&lt;span&gt;veth.up()
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;kind&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;veth&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;promiscuity&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;group&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ipdb_scope&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;system&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ifi_type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;linkmode&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ipdb_priority&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;carrier_changes&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;num_rx_queues&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;address&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;26:29:f4:06:8a:ea&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;mtu&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1500&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;carrier&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ifname&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;vp01&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;num_tx_queues&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;index&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ports&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;vlans&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ipaddr&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;qdisc&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;noop&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;neighbours&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;txqlen&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;broadcast&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ff:ff:ff:ff:ff:ff&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;operstate&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;DOWN&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;flags&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;4098&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;family&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;with &lt;&#x2F;span&gt;&lt;span&gt;ipdb_namespace1.interfaces.lo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;i:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...   &lt;&#x2F;span&gt;&lt;span&gt;i.up()
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#569cd6;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;flags&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;promiscuity&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;group&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ipdb_scope&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;system&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ifi_type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;772&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;linkmode&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ipdb_priority&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;carrier_changes&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;address&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;00:00:00:00:00:00&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;mtu&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;65536&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;carrier&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ifname&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;lo&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;num_tx_queues&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;index&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ports&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;vlans&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;ipaddr&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;qdisc&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;noop&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;neighbours&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [], &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;txqlen&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;broadcast&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;00:00:00:00:00:00&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;operstate&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;DOWN&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;num_rx_queues&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d69d85;&quot;&gt;&amp;#39;family&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b5cea8;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;At this point, we can open a shell and directly check the configuration for &lt;code&gt;v01&lt;&#x2F;code&gt; interface:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;kintanu:~# ip addr show v01
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;6: v01: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
&lt;&#x2F;span&gt;&lt;span&gt;    link&#x2F;ether f2:2d:aa:9d:16:da brd ff:ff:ff:ff:ff:ff
&lt;&#x2F;span&gt;&lt;span&gt;    inet 192.168.1.36&#x2F;24 scope global v01
&lt;&#x2F;span&gt;&lt;span&gt;       valid_lft forever preferred_lft forever
&lt;&#x2F;span&gt;&lt;span&gt;    inet6 fe80::f02d:aaff:fe9d:16da&#x2F;64 scope link
&lt;&#x2F;span&gt;&lt;span&gt;       valid_lft forever preferred_lft forever
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;We can also, still from the shell, check the available interfaces inside &lt;code&gt;namespace1&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;kintanu:~# ip netns exec namespace1 ip addr show
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt; mtu 65536 qdisc noqueue state UNKNOWN group default
&lt;&#x2F;span&gt;&lt;span&gt;    link&#x2F;loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
&lt;&#x2F;span&gt;&lt;span&gt;    inet 127.0.0.1&#x2F;8 scope host lo
&lt;&#x2F;span&gt;&lt;span&gt;       valid_lft forever preferred_lft forever
&lt;&#x2F;span&gt;&lt;span&gt;    inet6 ::1&#x2F;128 scope host
&lt;&#x2F;span&gt;&lt;span&gt;       valid_lft forever preferred_lft forever
&lt;&#x2F;span&gt;&lt;span&gt;5: vp01: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
&lt;&#x2F;span&gt;&lt;span&gt;    link&#x2F;ether 26:29:f4:06:8a:ea brd ff:ff:ff:ff:ff:ff
&lt;&#x2F;span&gt;&lt;span&gt;    inet 192.168.1.37&#x2F;24 scope global vpeer01
&lt;&#x2F;span&gt;&lt;span&gt;       valid_lft forever preferred_lft forever
&lt;&#x2F;span&gt;&lt;span&gt;    inet6 fe80::2429:f4ff:fe06:8aea&#x2F;64 scope link
&lt;&#x2F;span&gt;&lt;span&gt;       valid_lft forever preferred_lft forever
&lt;&#x2F;span&gt;&lt;span&gt;kintanu:~#
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;A system uses its routing table to determine which network interface to use when sending packets to remote systems. Let&#x27;s make all traffic leaving &lt;code&gt;namespace1&lt;&#x2F;code&gt; to go through &lt;code&gt;v01&lt;&#x2F;code&gt;:
&lt;a name=&quot;default-route-for-namespace&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;kintanu:~# ip netns exec namespace1 ip route add default via 192.168.1.36
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;nskm.xyz&#x2F;posts&#x2F;onn&#x2F;%7Bfilename%7D&#x2F;images&#x2F;default-route-added.png&quot; alt=&quot;Default route added&quot; &#x2F;&gt;
&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I told you I often use LXC containers when I&#x27;m working. For that reason, I always have a bridge configured and up. Then, all the containers are connected to the internet, via the bridge, as &lt;code&gt;ports&lt;&#x2F;code&gt;. Let me show you:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;kintanu:~# ip addr show br0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;4: br0: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc noqueue state UP group default
&lt;&#x2F;span&gt;&lt;span&gt;    link&#x2F;ether 3c:97:0e:65:c0:27 brd ff:ff:ff:ff:ff:ff
&lt;&#x2F;span&gt;&lt;span&gt;    inet 192.168.1.34&#x2F;24 brd 192.168.1.255 scope global br0
&lt;&#x2F;span&gt;&lt;span&gt;       valid_lft forever preferred_lft forever
&lt;&#x2F;span&gt;&lt;span&gt;    inet6 fe80::3e97:eff:fe65:c027&#x2F;64 scope link
&lt;&#x2F;span&gt;&lt;span&gt;       valid_lft forever preferred_lft forever
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;kintanu:~# brctl show
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;bridge name     bridge id               STP enabled     interfaces
&lt;&#x2F;span&gt;&lt;span&gt;br0             8000.3c970e65c027       no              eth0
&lt;&#x2F;span&gt;&lt;span&gt;                                                        vethLMRO1N
&lt;&#x2F;span&gt;&lt;span&gt;kintanu:~#
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
&lt;p&gt;The &lt;code&gt;br0&lt;&#x2F;code&gt; interface is the interface I use for going outside. In fact, &lt;code&gt;br0&lt;&#x2F;code&gt; is a bridge. &lt;code&gt;eth0&lt;&#x2F;code&gt; and &lt;code&gt;vethLMRON&lt;&#x2F;code&gt; are interfaces, &lt;code&gt;ports&lt;&#x2F;code&gt;, attached to that &lt;a href=&quot;http:&#x2F;&#x2F;www.linuxfoundation.org&#x2F;collaborate&#x2F;workgroups&#x2F;networking&#x2F;bridge&quot;&gt;bridge&lt;&#x2F;a&gt;. &lt;code&gt;v01&lt;&#x2F;code&gt; should be attached to the &lt;code&gt;br0&lt;&#x2F;code&gt; bridge, otherwise, &lt;code&gt;v01&lt;&#x2F;code&gt; won&#x27;t be able to send packets to the outside world:
&lt;a name=&quot;attach-veth-to-bridge&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;kintanu:~# brctl addif br0 v01
&lt;&#x2F;span&gt;&lt;span&gt;kintanu:~# brctl show
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#1e1e1e;color:#dcdcdc;&quot;&gt;&lt;code&gt;&lt;span&gt;bridge name     bridge id               STP enabled     interfaces
&lt;&#x2F;span&gt;&lt;span&gt;br0             8000.3c970e65c027       no              eth0
&lt;&#x2F;span&gt;&lt;span&gt;                                                        vethLMRO1N
&lt;&#x2F;span&gt;&lt;span&gt;                                                        v01
&lt;&#x2F;span&gt;&lt;span&gt;kintanu:~#
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;br&gt;
![Veth pair device added to bridge]({filename}&#x2F;images&#x2F;ns.png)
&lt;br&gt;&lt;br&gt;
If everything went fine, you should be able to ping an external host from `namespace1`:
```
kintanu:~# ip netns exec namespace1 ping 8.8.8.8
```
```
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
From 192.168.1.34: icmp_seq=1 Redirect Host(New nexthop: 192.168.1.1)
64 bytes from 8.8.8.8: icmp_seq=1 ttl=54 time=104 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=54 time=105 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=54 time=105 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=54 time=104 ms
^C
--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min&#x2F;avg&#x2F;max&#x2F;mdev = 104.190&#x2F;104.859&#x2F;105.375&#x2F;0.595 ms
kintanu:~#
```
&lt;br&gt;
&lt;p&gt;We&#x27;ve just seen how to create a network namespace, and link that network namespace to the outside world. When playing with LXC containers, you will also heard about &lt;code&gt;control groups&lt;&#x2F;code&gt;, a kernel mechanism that will allow you to allocate resources among user-defined groups of tasks (processes) running on a system. That will be the topic of the next chapter.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;&#x2F;p&gt;
&lt;p style=&quot;text-align: right;&quot;&gt;All the diagrams were made using [Asciiflow](http:&#x2F;&#x2F;asciiflow.com&#x2F;)&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Introduction</title>
        <published>2015-07-24T00:00:00+00:00</published>
        <updated>2015-07-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nskm.xyz/posts/intro/"/>
        <id>https://nskm.xyz/posts/intro/</id>
        
        <content type="html" xml:base="https://nskm.xyz/posts/intro/">&lt;p&gt;Hello, I&#x27;m Patrick, born and raised in central &lt;a href=&quot;#&quot;&gt;Africa&lt;&#x2F;a&gt;, currently based in West Africa, &lt;a href=&quot;#&quot;&gt;Dakar Senegal&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I am an experienced software engineer, passionate about &lt;a href=&quot;#&quot;&gt;free software&lt;&#x2F;a&gt;. I have a strong background in developing backend solutions. With almost 10 years of hands-on experience in the field, I have successfully contributed to &lt;a href=&quot;#&quot;&gt;free software&lt;&#x2F;a&gt; and I have successfully developed and deployed &lt;a href=&quot;#&quot;&gt;numerous&lt;&#x2F;a&gt; &lt;a href=&quot;#&quot;&gt;software&lt;&#x2F;a&gt; &lt;a href=&quot;#&quot;&gt;projects&lt;&#x2F;a&gt; &lt;a href=&quot;#&quot;&gt;across&lt;&#x2F;a&gt; &lt;a href=&quot;#&quot;&gt;various&lt;&#x2F;a&gt; &lt;a href=&quot;#&quot;&gt;industries&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;My expertise lies in &lt;a href=&quot;#&quot;&gt;free software&lt;&#x2F;a&gt;, &lt;a href=&quot;#&quot;&gt;Python programming&lt;&#x2F;a&gt;, &lt;a href=&quot;#&quot;&gt;databases&lt;&#x2F;a&gt;; enabling me to tackle complex challenges and deliver high-quality, scalable software solutions. I thrive in dynamic and collaborative environments, working closely with cross-functional teams to understand requirements, design architectures, and implement robust solutions.&lt;&#x2F;p&gt;
&lt;p&gt;Throughout my career, I have demonstrated a proven track record of delivering projects on time and within budget, while ensuring adherence to best practices and industry standards. I am adept at analyzing existing systems, identifying areas for improvement, and implementing enhancements that optimize performance and user experience.&lt;&#x2F;p&gt;
&lt;p&gt;Over the course of my professional journey, I have had the privilege of &lt;a href=&quot;#&quot;&gt;working as a programming instructor&lt;&#x2F;a&gt; for diverse groups of learners, ranging from beginners to experienced professionals. My &lt;a href=&quot;#&quot;&gt;teaching&lt;&#x2F;a&gt; approach is centered around creating an engaging and supportive &lt;a href=&quot;#&quot;&gt;learning environment&lt;&#x2F;a&gt;, where students can grasp complex concepts with ease and apply them effectively.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond technical skills, I am a team player, strong communicator and effective problem solver. I excel at sharing knowledge, at translating complex technical concepts into clear &amp;amp; non-technical language, fostering effective communication between stakeholders, clients, and development teams.&lt;&#x2F;p&gt;
&lt;p&gt;I am constantly exploring emerging technologies and &lt;a href=&quot;#&quot;&gt;staying up-to-date&lt;&#x2F;a&gt; with industry trends, as I believe in continuous learning and professional growth. I am eager to leverage my skills and expertise to contribute to a dynamic organization, driving innovation and delivering exceptional software solutions.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
