Skip to content

41st Week of 2022





Configure Docker to host the application

  • New: Update dockers with Renovate.

    Renovate is a program that does automated dependency updates. Multi-platform and multi-language.

  • New: Connect multiple docker compose files.

    You can connect services defined across multiple docker-compose.yml files.

    In order to do this you’ll need to:

    • Create an external network with docker network create <network name>
    • In each of your docker-compose.yml configure the default network to use your externally created network with the networks top-level key.
    • You can use either the service name or container name to connect between containers.

Python Snippets

  • New: Print datetime with a defined format.

    now =
    today.strftime('We are the %d, %b %Y')

    Where the datetime format is a string built from these directives.

  • New: Print string with asciiart.

    pip install pyfiglet
    from pyfiglet import figlet_format
    print(figlet_format('09 : 30'))

    If you want to change the default width of 80 caracteres use:

    from pyfiglet import Figlet
    f = Figlet(font="standard", width=100)
  • New: Print specific time format.'%Y-%m-%dT%H:%M:%S')

    Code Meaning Example %a Weekday as locale’s abbreviated name. Mon %A Weekday as locale’s full name. Monday %w Weekday as a decimal number, where 0 is Sunday and 6 is Saturday. 1 %d Day of the month as a zero-padded decimal number. 30 %-d Day of the month as a decimal number. (Platform specific) 30 %b Month as locale’s abbreviated name. Sep %B Month as locale’s full name. September %m Month as a zero-padded decimal number. 09 %-m Month as a decimal number. (Platform specific) 9 %y Year without century as a zero-padded decimal number. 13 %Y Year with century as a decimal number. 2013 %H Hour (24-hour clock) as a zero-padded decimal number. 07 %-H Hour (24-hour clock) as a decimal number. (Platform specific) 7 %I Hour (12-hour clock) as a zero-padded decimal number. 07 %-I Hour (12-hour clock) as a decimal number. (Platform specific) 7 %p Locale’s equivalent of either AM or PM. AM %M Minute as a zero-padded decimal number. 06 %-M Minute as a decimal number. (Platform specific) 6 %S Second as a zero-padded decimal number. 05 %-S Second as a decimal number. (Platform specific) 5 %f Microsecond as a decimal number, zero-padded on the left. 000000 %z UTC offset in the form +HHMM or -HHMM (empty string if the the object is naive). %Z Time zone name (empty string if the object is naive). %j Day of the year as a zero-padded decimal number. 273 %-j Day of the year as a decimal number. (Platform specific) 273 %U Week number of the year (Sunday as the first day of the week) as a zero padded decimal number. All days in a new year preceding the first Sunday are considered to be in week 0. 39 %W Week number of the year (Monday as the first day of the week) as a decimal number. All days in a new year preceding the first Monday are considered to be in week 0. %c Locale’s appropriate date and time representation. Mon Sep 30 07:06:05 2013 %x Locale’s appropriate date representation. 09/30/13 %X Locale’s appropriate time representation. 07:06:05 %% A literal '%' character. %


  • New: Introduce ICS.

    ics is a pythonic iCalendar library. Its goals are to read and write ics data in a developer-friendly way.


  • New: Live display text.

    import time
    from import Live
    with Live("Test") as live:
        for row in range(12):
            live.update(f"Test {row}")

    If you don't want the text to have the default colors, you can embed it all in a Text object.


  • New: Click on element.

    Once you've opened the page you want to interact with driver.get(), you need to get the Xpath of the element to click on. You can do that by using your browser inspector, to select the element, and once on the code if you right click there is a "Copy XPath"

    Once that is done you should have something like this when you paste it down.


    Similarly it is the same process for the input fields for username, password, and login button.

    We can go ahead and do that on the current page. We can store these xpaths as strings in our code to make it readable.

    We should have three xpaths from this page and one from the initial login.

    first_login = '//*[@id=”react-root”]/section/main/article/div[2]/div[2]/p/a'
    username_input = '//*[@id="react-root"]/section/main/div/article/div/div[1]/div/form/div[2]/div/label/input'
    password_input = '//*[@id="react-root"]/section/main/div/article/div/div[1]/div/form/div[3]/div/label/input'
    login_submit = '//*[@id="react-root"]/section/main/div/article/div/div[1]/div/form/div[4]/button/div'

    Now that we have the xpaths defined we can now tell Selenium webdriver to click and send some keys over for the input fields.

    from import By
    driver.find_element(By.XPATH, first_login).click()
    driver.find_element(By.XPATH, username_input).send_keys("username")
    driver.find_element(By.XPATH, password_input).send_keys("password")
    driver.find_element(By.XPATH, login_submit).click()
  • New: Bypass Selenium detectors.

    Sometimes web servers react differently if they notice that you're using selenium. Browsers can be detected through different ways and some commonly used mechanisms are as follows:

    • Implementing captcha / recaptcha to detect the automatic bots.
    • Non-human behaviour (browsing too fast, not scrolling to the visible elements, ...)
    • Using an IP that's flagged as suspicious (VPN, VPS, Tor...)
    • Detecting the term HeadlessChrome within headless Chrome UserAgent
    • Using Bot Management service from Distil Networks, Akamai, Datadome.

    They do it through different mechanisms:

    If you've already been detected, you might get blocked for a plethora of other reasons even after using these methods. So you may have to try accessing the site that was detecting you using a VPN, different user-agent, etc.


Infrastructure as Code


  • New: Introduce gitea.

    Gitea is a community managed lightweight code hosting solution written in Go. It's the best self hosted Github alternative in my opinion.

Automating Processes


  • New: Introduce Renovate.

    Renovate is a program that does automated dependency updates. Multi-platform and multi-language.

    Why use Renovate?

    • Get pull requests to update your dependencies and lock files.
    • Reduce noise by scheduling when Renovate creates PRs.
    • Renovate finds relevant package files automatically, including in monorepos.
    • You can customize the bot's behavior with configuration files.
    • Share your configuration with ESLint-like config presets.
    • Get replacement PRs to migrate from a deprecated dependency to the community suggested replacement (npm packages only).
    • Open source.
    • Popular (more than 9.7k stars and 1.3k forks)
    • Beautifully integrate with main Git web applications (Gitea, Gitlab, Github).
    • It supports most important languages: Python, Docker, Kubernetes, Terraform, Ansible, Node, ...



  • New: Analyze RAM to buy.

    Most ZFS resources suggest using ECC RAM. The provider gives me two options:

    • Kingston Server Premier DDR4 3200MHz 16GB CL22
    • Kingston Server Premier DDR4 2666MHz 16GB CL19

    I'll go with two modules of 3200MHz CL22 because it has a smaller RAM latency.

  • New: Analyze motherboard to buy.

    After reading these reviews(1, 2) I've come to the decision to purchase the ASRock X570M Pro4 because, It supports:

    • 8 x SATA3 disks
    • 2 x M.2 disks
    • 4 x DDR4 RAM slots with speeds up to 4200+ and ECC support
    • 1 x AMD AM4 Socket Ryzen™ 2000, 3000, 4000 G-Series, 5000 and 5000 G-Series Desktop Processors
    • Supports NVMe SSD as boot disks
    • Micro ATX Form Factor.

    And it gives me room enough to grow:

    • It supports PCI 4.0 for the M.2 which is said to be capable of perform twice the speed compared to previous 3rd generation. the chosen M2 are of 3rd generation, so if I need more speed I can change them.
    • I'm only going to use 2 slots of RAM giving me 32GB, but I could grow 32 more easily.
  • New: Analyze CPU to buy.

    After doing some basic research I'm between:

    Property Ryzen 7 5800x Ryzen 5 5600x Ryzen 7 5700x Ryzen 5 5600G
    Cores 8 6 8 6
    Threads 16 12 16 12
    Clock 3.8 3.7 3.4 3.9
    Socket AM4 AM4 AM4 AM4
    PCI 4.0 4.0 4.0 3.0
    Thermal Not included Wraith Stealth Not included Wraith Stealth
    Default TDP 105W 65W 65W 65W
    System Mem spec >= 3200 MHz >= 3200 MHz >= 3200 MHz >= 3200 MHz
    Mem type DDR4 DDR4 DDR4 DDR4
    Price 315 232 279 179

    The data was extracted from AMD's official page.

    They all support the chosen RAM and the motherboard.

    I'm ruling out Ryzen 7 5800x because it's too expensive both on monetary and power consumption terms. Also ruling out Ryzen 5 5600G because it has comparatively bad properties.

    Between Ryzen 5 5600x and Ryzen 7 5700x, after checking these comparisons (1, 2) it looks like:

    • Single core performance is similar.
    • 7 wins when all cores are involved.
    • 7 is more power efficient.
    • 7 is better rated.
    • 7 is newer (1.5 years).
    • 7 has around 3.52 GB/s (7%) higher theoretical RAM memory bandwidth
    • They have the same cache
    • 7 has 5 degrees less of max temperature
    • They both support ECC
    • 5 has a greater market share
    • 5 is 47$ cheaper

    I think that for 47$ it's work the increase on cores and theoretical RAM memory bandwidth.

  • New: Analyze CPU coolers to buy.

    It looks that the Ryzen CPUs don't require a cooler to work well. Usually it adds another 250W to the consumption. I don't plan to overclock it and I've heard that ZFS doesn't use too much CPU, so I'll start without it and monitor the temperature.

    If I were to take one, I'd go with air cooling with something like the Dark Rock 4 but I've also read that Noctua are a good provider.

  • New: Analyze server cases to buy.

    I'm ruling out the next ones:

    • Fractal Design R6: More expensive than the Node 804 and it doesn't have hot swappable disks.
    • Silverstone Technology SST-CS381: Even though it's gorgeous it's too expensive.
    • Silverstone DS380: It only supports Mini-ITX which I don't have.

    The remaining are:

    Model Fractal Node 804 Silverstone CS380
    Form factor Micro - ATX Mid tower
    Motherboard Micro ATX Micro ATX
    Drive bays 8 x 3.5", 2 x 2.5" 8 x 3.5", 2 x 5.25"
    Hot-swap No yes
    Expansion Slots 5 7
    CPU cooler height 160mm 146 mm
    PSU compatibility ATX ATX
    Fans Front: 4, Top: 4, Rear 3 Side: 2, Rear: 1
    Price 115 184
    Size 34 x 31 x 39 cm 35 x 28 x 21 cm

    I like the Fractal Node 804 better and it's cheaper.


  • New: Choosing the cold spare disks.

    It's good to think how much time you want to have your raids to be inconsistent once a drive has failed.

    In my case, for the data I want to restore the raid as soon as I can, therefore I'll buy another rotational disk. For the SSDs I have more confidence that they won't break so I don't feel like having a spare one.



  • New: Introduce CPU, attributes and how to buy it.

    A central processing unit or CPU, also known as the brain of the server, is the electronic circuitry that executes instructions comprising a computer program. The CPU performs basic arithmetic, logic, controlling, and input/output (I/O) operations specified by the instructions in the program.


  • New: Introduce RAM, it's properties and how to buy it.

    RAM is a form of computer memory that can be read and changed in any order, typically used to store working data and machine code.

Operating Systems



  • New: Introduce i3wm.

    i3 is a tiling window manager.

  • New: Layout saving.

    Layout saving/restoring allows you to load a JSON layout file so that you can have a base layout to start working with after powering on your computer.

    First of all arrange the windows in the workspace, then you can save the layout of either a single workspace or an entire output:

    i3-save-tree --workspace "1: terminal" > ~/.i3/workspace-1.json

    You need to open the created file and remove the comments that match the desired windows under the swallows keys, so transform the next snippet:

        "swallows": [
            //  "class": "^URxvt$",
            //  "instance": "^irssi$"


        "swallows": [
                "class": "^URxvt$",
                "instance": "^irssi$"

    Once is ready close all the windows of the workspace you want to restore (moving them away is not enough!).

    Then on a terminal you can restore the layout with:

    i3-msg 'workspace "1: terminal"; append_layout ~/.i3/workspace-1.json'

    It's important that you don't use a relative path

    Even if you're in ~/.i3/ you have to use i3-msg append_layout ~/.i3/workspace-1.json.

    This command will create some fake windows (called placeholders) with the layout you had before, i3 will then wait for you to create the windows that match the selection criteria. Once they are, it will put them in their respective placeholders.

    If you wish to create the layouts at startup you can add the next snippet to your i3 config.

    exec --no-startup-id "i3-msg 'workspace \"1: terminal\"; append_layout ~/.i3/workspace-1.json'"


  • New: Edit the events in a more pleasant way.

    The ikhal event editor is not comfortable for me. I usually only change the title or the start date and in the default interface you need to press many keystrokes to make it happen.

    A patch solution is to pass a custom script on the EDITOR environmental variable. Assuming you have questionary and ics installed you can save the next snippet into an edit_event file in your PATH:

    """Edit an ics calendar event."""
    import sys
    import questionary
    from ics import Calendar
    file = sys.argv[1]
    with open(file, "r") as fd:
        calendar = Calendar(
    event = list(calendar.timeline)[0] = questionary.text("Title: ",
    start = questionary.text(
        "Start: ",
    event.begin = event.begin.replace(
        hour=int(start.split(":")[0]), minute=int(start.split(":")[1])
    with open(file, "w") as fd:

    Now if you open ikhal as EDITOR=edit_event ikhal, whenever you edit one event you'll get a better interface. Add to your .zshrc or .bashrc:

    alias ikhal='EDITOR=edit_event ikhal'

    The default keybinding for the edition is not very comfortable either, add the next snippet on your config:

    ini [keybindings] external_edit = e export = meta e