Conda (Miniconda) Cheatsheet: Essential Commands You Should Know


This cheatsheet is a summary of the common commands I use. It serves as a quick reference to the most important Conda (Miniconda) commands and as a reminder for myself.

What is Conda?

Conda is a package and environment management system, widely used in the Python and data science community. It allows you to separate projects into environments and install packages into them, making it easy to manage dependencies and avoid conflicts between packages. It also helps to replicate a specific environment in another computer.

MiniConda is a minimal installer for Conda. It includes only Conda, Python, and a few essential packages, and it's managed thought the terminal.

Essential Conda Commands:

1. Installing Conda (Miniconda):

  • Download Miniconda: Visit the official Miniconda page and download the installer for your OS.
  • Install Miniconda: Follow the installation instructions provided on the download page. In Linux that means running the following:
mkdir -p ~/miniconda3
wget -O ~/miniconda3/
bash ~/miniconda3/ -b -u -p ~/miniconda3
rm -rf ~/miniconda3/ # if you don't want to keep the installer

You need to initialize conda for your shell for it to work:

~/miniconda3/bin/conda init bash
~/miniconda3/bin/conda init zsh

and restart your terminal or run source ~/.bashrc or source ~/.zshrc for the changes to take effect.

2. Managing Environments:

  • Create an Environment: conda create --name myenv
  • Activate an Environment: conda activate myenv
  • Deactivate an Environment: conda deactivate
  • List all Environments: conda env list
  • Remove an Environment: conda env remove --name myenv
  • Clone an Environment: conda create --name myclone --clone myenv
  • Create an Environment from a File: conda env create -f environment.yml
  • Update an Environment from a File: conda env update -f environment.yml
  • Export an Environment to a File: conda env export > environment.yml

  • Export an Environment to a File (including Conda itself): conda list --explicit > environment.yml

  • Create an Environment from a File (including Conda itself): conda create --name myenv --file environment.yml
  • Update an Environment from a File (including Conda itself): conda update --name myenv --file environment.yml

3. Managing Packages:

from Conda:

this is the main and default repository for conda packages.

  • Install a Package: conda install numpy
  • Uninstall a Package: conda remove numpy
  • List Installed Packages: conda list
  • Update a Package: conda update numpy
  • Search for a Package: conda search numpy

from conda repositories:

There are alternative repositories to the default one, such as conda-forge and bioconda. You can install packages from these repositories by specifying the channel.

  • Install a Package from conda-forge: conda install -c conda-forge numpy
  • Install a Package from bioconda: conda install -c bioconda numpy

from Pip:

Some packages are not in conda, so you need to use pip to install them. pip is the default package manager for Python.

  • Install Pip, if its not installed: conda install pip
  • Install a Package: pip install numpy

4. Updating Conda:

To update conda itself, you need to update the base environment. This means deactivating the environment you are in and updating the base environment.

  • Update Conda: conda update conda

5. Exporting and Importing Environments:

  • Export Environment: conda env export > environment.yml
  • Create Environment from a File: conda env create -f environment.yml

6. Miscellaneous Commands:

  • List Conda Commands: conda --help
  • Check Conda Version: conda --version


  • [Conda Official Documentation](

The Role of User Feedback and Research in UX | UX Series Part 2 of 6


In the field of User Experience (UX) design, understanding and integrating user feedback is paramount. This insight is crucial during the discovery phase, where proximity to the issue can often lead to overlooked user needs.

What does this mean? It means that designers, product owners, product manager, and other team members are often too close to the project to see the bigger picture. They are too familiar with the product to identify its flaws and shortcomings.

You may also call this "expert blindness", which is the inability to see something in the eyes of a beginner (or non-expert). This is a common problem in many fields, and it's also a common problem in UX design.

Fictional real-life-problem example

There are many examples of this, but one common one is the following situation:

Please take into account that this is a fictional example, but it's based on real-life situations.

A user is trying to perform a task on a website or app, but they can't find the button or link to do it. This user calls support and asks for help, and supports does not understand the problem (because they explain where the button is and the user cannot find it) and ask the user to create a ticket and add a screenshot of the problem. Support then derives the ticket to the product owner (because, who knows a product better than the product owner, correct?) and the product owner cannot understand how no one can find the button, because it's right there, under the form, on the right side, with a red background and a white text that says "Submit".

You already saw the problem, right? The button is there, but it's not obvious to the user. In all the other systems the user uses, submit is with a green background and a white text, or something like that. The user is used to button with red background to mean "cancel" or "delete", and they are not used to a red button meaning "submit", so he probably didn't even see it or thought it was a "cancel" button and didn't click it.

This is a common problem, and it's a problem that can be solved with user feedback and research.

User Feedback

The importance of user feedback, not only in UX, but in any field, cannot be overstated. It helps us to understand the experience of users and their expectations, their needs, and their preferences. This insight is crucial in creating effective digital solutions (and also other kind of solutions).

We can divide user feedback into two phases:

  1. Discover Phase: User feedback helps identify real needs and preferences, which might be missed by designers and team members too close to the project. This should be done at the beginning of the project.
  2. Continual Improvement Phase: Regular feedback ensures that the UX design remains relevant and user-centric. This is a continuous process that should be done throughout the project and lifecycle of the product. It helps us identify problems and opportunities for improvement and helps us understand how users interact with the product after the initial phase. For example, you may be able to understand the differences in user behavior between heavy users and light users of your product, and you may be able to identify opportunities to improve the experience of both.

User Research Methods

User research methods come, in my experience, from regular research methods and share common characteristics with other kinds of research, such as market research.

Effective user research employs various techniques, such as:

  1. Focus Groups: Gathering diverse user perspectives by talking to a representative sample of our target users. Due to the costs and difficulty of coordinating such groups, we often decide on small groups that the team feels can provide appropriate feedback.
  2. Surveys and Questionnaires: Collecting quantifiable data on user preferences. This requires careful planning to ensure that the questions are clear and unbiased and that the data (answers) you collect is relevant to the project.
  3. Market Research: Understanding broader market trends and user behaviors. You need to correctly design a market research study to ensure that you get the data you need. (This is a topic for another article)
  4. Observation of Existing Solutions: Learning from current market offerings. I think of this as an exploratory analysis.
  5. Formal Lab Usability Studies: In-depth analysis of user interactions with the product.

It's crucial to approach user research without leading users to specific answers, ensuring unbiased and genuine insights, even if they are not what we expected and even if this means more work for us to process the data.

Free text answers are often the most valuable, but they are also the most difficult to process and less likely to be filled by users. This is why it's important to have a mix of different types of questions in your research. For free text answers you can use tools (if you have to many answers to process manually). I would recommend, if you can, to use Python, R or Julia and Natural Language Processing, Sentiment Analysis, and other techniques to process the data. (this is also a topic for another article).

Creating Personas, Marketing Personas or Target Audience Profiles

Creating personas belongs usually to the Discover Phase of the UX design process. Personas are fictional profiles of typical users, representing their needs, preferences, and behaviors. They help simplify the design process and also simplify the internal communication of the team.

A typical persona includes:

  • Name: A name that represents the persona. (it's easier to remember a name than a number and gives the team the feeling that they are working for a real person)
  • Photo: A photo of the persona. (it's easier to remember a face than a name)
  • Needs: The needs of the persona. (what they need to do)
  • Demographics: age, gender, household income, education/ occupation, location, etc. (this is not always relevant, but it's good to have it)
  • Interests: hobbies, interests, etc.
  • Behaviors: how they interact with the product, how often they use it, etc.
  • Goals: what they want to achieve with the product. (some profiles use this and I find it important)

Key takeaways

UX is complex and requires you to understand the user, its needs and expectations. Given the fact that most teams are experts in their products, user feedback and research become indispensable tools in the UX design process. They provide the foundation for understanding user needs and crafting experiences that resonate with them.

Emphasizing these aspects ensures that the final product is not only functional but also aligns with user expectations and preferences and allows your team to build a product that users will love (and therefor buy and recommend).

Understanding User Experience (UX) | UX Series Part 1 of 6


User Experience (UX), also known as User-Centered Design (UCD), is a crucial aspect of digital skills. It extends beyond the User Interface (UI), which is merely how users interact on a screen. UX encompasses every interaction that a customer has with a business, both online and offline.

... so user experience design is something that begins at the very start of an idea, and it goes all the way through the lifetime of your product or your site.

-- User Experience (UX)

The Essence of UX

UX design begins at the inception of an idea and continues throughout the product's lifespan. It's about understanding and addressing the needs and preferences of users. The process involves:

  1. Researching Users: Understanding their needs, likes, and dislikes.
  2. Iterative Feedback: Continuously refining the design based on user feedback.

A well-designed UX minimizes pain points in the user journey, ensuring a successful and intuitive design.

UX is all about minimising those pain points in the journey to ensure that your website has the most successful design possible.

-- User Experience (UX)

Foundations of UX Design

There are three key foundations or ideas of UX design:

1. User-Centered Mind-Set

Focus on trying to understand the user, approaching with curiosity and asking questions like "Why?" and "What if?".

  • Don't assume that you know what the user wants and needs
  • Don't assume that you know what the solution is.

2. Key Stages of UX Process

  • Discover: Research and understand the user.
  • Describe: Define the problem and the solution.
  • Design: Create a prototype.
  • Develop: Build the product.
  • Continuously improve: Test and refine the product based on user feedback.

3. Principles of Good Usability

  • Simplicity: Keep it simple. Complexity is the enemy of good design.
  • Intuitiveness: Make it easy to use. Your user should not need a manual to use your product if you can prevent it. (No one reads manuals anyway because is always easier to google it or call support.)
  • Engagement: Make it enjoyable to use.
    • This is not always possible, but it is a good goal to have.
    • If you can't make it enjoyable, at least make it not annoying.
  • Efficiency: Make it fast to use or at least make it feel fast or not slow.
  • Support: Provide easy-to-access support when needed, but don't make it necessary.
  • Error recovery: Make it easy to recover from errors.
  • Consistency: Make it consistent throughout the product. The customer should not feel like they are using
    products from different companies when they are just using different parts of your product.

Best Practices in UX

  • Placement of menus and icons: place the menu where the user expects it to be -> top or left side.
  • Consistent design throughout the product: consistent colors, fonts, icons, layout, etc.
  • Attention to details that enhance user retention. If you can make the user feel good about using your product, they will come back and be happy with what they bought. If they don't feel good, they will regret their buying decision.


An effective UX team comprises members from diverse backgrounds, enriching the design process with varied perspectives.

Tools for UX Design

Various tools aid in UX design, such as:

Key takeaways

UX design is a dynamic, ongoing process integral to the success of any (digital) product. It requires a deep understanding of the user and a commitment to continual improvement based on feedback and evolving user needs. It also requires a multidisciplinary team with diverse perspectives and skills.

Yet another ASCIIDoc, Markdown and RestructuredText cheatsheet

This article is a cheatsheet/ summary on the (my) most used markup languages. It is not a tutorial, but a quick reference for those who already know the basics of each markup language.
This article is a work-in-progress and has a long table with many columns. If you are reading this on a mobile device, you may want to switch to landscape mode or use a bigger screen.


I write using , and depending on the kind of text. Each has its pros and contras, and I think that using the right tool for each job makes a lot of sense.

This article is a cheatsheet of the most common elements I use in each markup language. I will be updating it as I find/ remember elements that I need to use. == TLDR

Markdown is my go-to for simple articles, RestructuredText for complex web content, and ASCIIDoc for long-form, feature-rich projects. Understanding the strengths and limitations of each helps me optimize my content creation process.

Because of that my use of markup languages is usually as follows:

Markdown: For Simplicity and Readability

  • When I Use It: Ideal for articles that don’t require complex formatting. I often use it for posts without a Table of Contents or advanced code snippets. That is the case in most of the articles I write and all my personal notes.

  • Why: Markdown’s simplicity and readability make it perfect for quick, clean content. It helps me keep the structure lean and stay focused on the content.

  • Limitations: I avoid using Markdown for content needing advanced elements like admonitions or tables, as these are challenging to implement effectively in Markdown. For some of this features, I wrote some shortcodes for Nikola (the static site generator I use).

RestructuredText: For Web Content Richness

  • When I Use It: Chosen for articles on my website that demand more sophisticated elements. I use it mainly for articles with admonitions.

  • Why: Its support for directives like tables, admonitions, notes, and warnings makes RestructuredText versatile for web-centric content.

  • Flexibility: It strikes a balance between simplicity and advanced formatting, filling the gap where Markdown falls short. (Although I have to admit that I am not a big fan of the syntax, such as the headings)

ASCIIDoc: For long-form articles and books

  • When I Use It: My preference for long-form articles, books, and other comprehensive documentation. I am using it for my book on digital marketing

  • Why: ASCIIDoc’s rich feature set allows for intricate structure and extensive customization. Its ability to include external files, define variables, and apply themes makes it unbeatable for complex projects.

  • Output Variety: The flexibility to compile content into formats like EPUB, PDF, and HTML is particularly valuable for diverse publishing needs.

Comparison Table

Table 1. Markup languages comparison and cheatsheet
Element Markdown Rest ASCIIDoc


# Header 1

## Header 2

### Header 3

#### Header 4
Header 1

Header 2

Header 3

Header 4
= Header 1

== Header 2

=== Header 3

==== Header 4


This is [an example]( "Title") inline link.

[This link]( has no title attribute.

`Python <>`_

`Internal and External links`_[]

Ask questions in the[*community chat*].

he section <<anchors>> describes how automatic anchors work.

Bold text

**Bold text**
**Bold text**
**Bold text**

Italic text

*Italic text*
*Italic text*
_Italic text_

underlined text

[.underline]#underlined text#

underlined text

Strikethrough text

~~Strikethrough text~~

Custom style (role in Asciidoc)

[.myrole]#custom role# must be fulfilled by the theme.

Quotation (simple)

> Quotation

Quotation (with author and title)

> Author
>    Title
> Quotation
> -- Author
> ====


   -- Author
[quote,attribution,citation title and information]
Quote or excerpt text

[quote, Author, Title]

Check for more information.

Code snippets

`this is an inline code`

this is a block of code with highlighting
.. code-block:: ruby

   Some Ruby code.
.. code-block:: ruby
   :lineno-start: 10

   Some more Ruby code, with line numbering starting at 10.
.. code-block:: python
   :emphasize-lines: 3,5

   def some_function():
       interesting = False
       print('This line is highlighted.')
       print('This one is not...')
       print('...but this one is.')

This is a directive with many options. Check for more information.

[source, python]
import pandas as pd

df = pd.DataFrame({'col1': [1, 2], 'col2': [3, 4]})
# more code

if you want to put a code snippet in a bullet point list or similar, you have to add it in a new line after a +. This way it will have the same indentation and will be part of the same div

- point in bullet point list
[source, python]
# here goes your code

Image (simple)

![Alt text](/path/to/img.jpg)
.. image:: /path/to/img.jpg
.Image title




Table (simple) (Source)

| Header 1 | Header 2 | Header 3 |
| Row 1    | Data 1   | Data 2   |
| Row 2    | Data 3   | Data 4   |

rst-simple-table-example.rst (Source)

.. table::
   :class: my-table

   | Header 1   | Header 2   | Header 3   |
   | Row 1      | Data 1     | Data 2     |
   | Row 2      | Data 3     | Data 4     |

asciidoc-simple-table-example.adoc (Source)

| Header 1 | Header 2 | Header 3
| Row 1 | Data 1 | Data 2
| Row 2 | Data 3 | Data 4

References in-document (simple)

[reference to a section](#section)

# Section
.. _my-reference-label:

Section Title

See :ref:`my-reference-label`

set the anchor


call the anchor. Thsi will use the title of the section it refers to.


Table (with code snippet)


asciidoc-table-with-code-snippet.adoc (Source)

a| Source code example:

print("Hello, World!")

Line/ Separator

.. line-block::

By the way, this article and cheatsheets were made using asciidoc and the Nikola Listings feature.

How to Read Large CSV Files with Pandas Without Knowing its Column Data Types

TLDR: read a sample of the data, infer the data types, and read the full data with the inferred data types.


Reading large (and sometimes not so large) CSV files in Pandas is a common problem. It is not uncommon to find CSV files with millions of rows and hundreds of columns, and sometimes the data types of the columns are unknown.


1. Read a sample of the data

Use nrows parameter

The first step is to read a sample of the data. This is done with the nrows parameter of the read_csv function.

This helps in understanding the data structure without loading the entire file into memory.

import pandas as pd

df = pd.read_csv('data.csv', nrows=1000)

The nrows parameter can be set to any number, but it is recommended to use a number that is large enough to get an idea of the data structure, but small enough to not use too much memory.

Use usecols parameter

You can also use less memory by reading only a subset of the columns with the usecols parameter, if you already know which columns you need to use.

import pandas as pd

df = pd.read_csv('data.csv', nrows=1000, usecols=['col1', 'col2'])

Use nrows and usecols parameter together

You can use both parameters together to read a sample of the data and only a subset of the columns.

import pandas as pd

df = pd.read_csv('data.csv', nrows=1000, usecols=['col1', 'col2'])

2. Inspect Data Types

Use dtypes attribute

The next step is to inspect the data types of the columns. This is done with the dtypes attribute of the dataframe.


3. Define data types manually

Based on the analysis of the data sample, you can define the data types of the columns manually.

from datetime import datetime, timedelta

dtypes_dict = {
    'col_str': str,                  # String
    'col_int': int,                  # Integer
    'col_float': float,              # Float
    'col_bool': bool,                # Boolean
    'col_datetime': datetime,        # Datetime
    'col_timedelta': timedelta,      # Timedelta
    'col_category': 'category',      # Category
    'col_complex': complex,          # Complex number
    'col_bytes': bytes,              # Bytes
    'col_object': object             # Generic Python object

Here are the Pandas dtypes for reference.

Some of the not-so-common data types are:

  • category: A pandas Categorical type. Useful for columns with a limited number of unique values. (e.g. gender, country, city, etc.). Check Categorical data for more information.
  • complex: A complex number. Check Complex Numbers for more information.
  • bytes: A sequence of bytes. Check Bytes and Bytearray for more information.
  • object: A generic Python object. Check Object for more information.
  • datetime: A datetime object is a single object containing all the information from a date object and a time object. Check datetime for more information.
  • timedelta: A timedelta object represents a duration, the difference between two dates or times. Check timedelta for more information.

4. Read the full data with the manually-defined data types

The next step is to load the data with the manually-defined data types from the earlier step.

For this, you can use the dtype parameter of the read_csv function.

import pandas as pd

df = pd.read_csv('data.csv', dtype=dtypes_dict)


If you get a ValueError, it means that the data types you defined are not compatible with all the data in the file, and you should check the data types again by using more rows or other chunks of the data. For that you may also use skiprows parameter.

import pandas as pd

df = pd.read_csv('data.csv', skiprows=1000, nrows=1000)

5. Use chunksize parameter if the data is too large to fit in memory

If using the options above is not enough to load the data into memory, you can use the chunksize parameter, which returns an iterator that can be used to read the data.

import pandas as pd

df_iterator = pd.read_csv('data.csv', chunksize=1000)

for df in df_iterator:
    # do something with df


Introducing my Custom Shortcodes for Nikola Static Site Generator


I introduce three new custom shortcodes for Nikola: series-button, infobox, and disclaimer. Each shortcode offers simple functionalities to streamline your Nikola site's design and user experience, and prevent you from repeating yourself.


Nikola, the Python-based static site generator I use for this website, allows the use of something called shortcodes. A shortcode is a simple snippet of code that can be used to add functionality to your website.

While writing some of my new posts, I realized that I was repeating myself a lot. I was adding the same buttons, some info boxes, and disclaimers. So I decided to create some custom shortcodes to make my life easier and make them available for others.

These shortcodes are designed for practical use and are available under the MIT License.

Shortcodes Overview


  • Template Engine: Jinja2
  • Usage: series-button-md-html-example.html (Source)
    {{% series_buttons previous_url="/previous-article" previous_text="Previous Article" next_url="/next-article" next_text="Next Article" %}}
  • Functionality:
  • Renders navigation buttons for article series.
  • Omitting previous_url or next_url will skip the respective button.
  • Defaults to "Previous in series" or "Next in series" if texts are not specified.
  • Customizable with CSS (#series-buttons ID).
  • Use Bootstrap 4 classes for styling.


  • Template Engine: Jinja2
  • Usage: infobox-md-html-example.html (Source)
    {{% infobox type="book" text="This is a book infobox" disclaimer="true" %}}
  • Example:
    • Functionality:
  • Displays an infobox for various content types.
  • Supports font-awesome icons: book, video, audio, link, quote, image, sticky-note.
  • Optional disclaimer can be added.
  • Use Bootstrap 4 classes for styling.


How to Use and Why

Integrating these shortcodes into your Nikola site is straightforward. Simply add the shortcode in your content where you want the feature to appear.

  • Series-button: Ideal for multipart articles or blogs, it allows easy navigation between series entries, improving user experience.
  • Infobox: Useful for highlighting information, such as book recommendations or important notices, making your content more interactive and engaging.
  • Disclaimer: Adds necessary legal or ethical notifications efficiently, ensuring transparency with your audience.

These shortcodes save time and maintain consistency across your site, adhering to the DRY principle.

They also allow you to focus on the content, not the code, and to update their content and styles in one place, instead of having to update it in every article.

Installation Guide

To install these shortcodes in your Nikola site, follow these steps:

  1. Go to and download the shortcodes you want to use.
  2. Copy the shortcodes to your Nikola site's shortcodes directory. If this directory doesn't exist, create it in your site's root directory.
  3. Add the shortcodes to your article. See the shortcode overview above for usage instructions.
  4. Run nikola build to build your site.
  5. Run nikola serve to preview your site.

Remember, these shortcodes are flexible and can be customized to fit the style and needs of your website. Once you download them and add them to your shortcodes directory, you can modify them as you wish, changing the HTML, CSS and text to suit your needs.


  1. Custom Shortcodes for Nikola on GitHub
  2. Official Nikola Shortcodes Repository


These shortcodes are available under the MIT License. See the MIT LICENSE file for more information.

How to Deploy a Nikola Static Site on Cloudflare Pages: A Step-by-Step Guide

Context: Nikola Static Site Generator

Static websites have become increasingly popular in the web development world for their speed, security, and simplicity. Nikola, a widely-used Python-based static site generator, facilitates the creation of content-rich yet lightweight websites.

You can use many markup-languages allowing you to choose the ones you like the most. You can even write some articles in Markdown, some in Asciidoc, some in reST and some in HTML, and Nikola will process them accordingly.

There are many other SSGs (Static Site Generators) out there, like Jekyll, Hugo, Eleventy, Gatsby, Hexo, MkDocs, Pelican, Zola, and many more. I’ve tried many of them (at list all them in the list above,) and I’ve found Nikola to be the best for my needs.

Your needs might be different, so I encourage you to try them all and choose the one that fits you the best. If in doubt, I recommend you to start with Nikola.

If you write all your content in Markdown, you can write a couple of articles and try each framework out there. The only thing you may have to change is the metadata format.

Anyway, this article is not about Nikola, but about how to deploy a Nikola site on Cloudflare Pages. and the steps described here can be applied to any other SSG, as long as you use the correct file for their dependency manager.

There is a list of supported SSGs (Frameworks) in the Cloudflare Pages documentation.

Hosting options like GitHub Pages, GitLab Pages, and Cloudflare Pages provide free, reliable and fast platforms for these kind of sites.

Why Cloudflare Pages?

Cloudflare Pages stands out, in my opinion, for:

  • its performance optimization and enhanced security (includes a basic WAF - Web Application Firewall - and DDoS protection),

  • its integration with their awesome DNS management,

  • integrated analytics (although with data for the last 30 days only),

  • its integration with Cloudflare CDN and proxy,

  • its free subdomain under (if you need one),

  • its free SSL certificate,

  • its multi-branch deployments (meaning you can deploy different branches to different subdomains and check if everything looks like you want before merging to master. You can also always re-deploy an old commit), and

  • its support for custom domains,

making it an excellent choice for hosting Nikola sites (or any kind of static sites, actually).

But the main reason I chose Cloudflare Pages is that it has Deploy hooks!

What are Deploy Hooks? → Automatic scheduled posts in static sites!

Deploy hooks are URLs that you can use to trigger a new deployment of your site. This is useful when you want to automate the deployment of your site, for example, when you push a new commit to your repository, or when you use Nikola to schedule posts in the future.

With deploy hooks I can set up a Zap in Zapier or a Flow in ActivePieces to trigger a rebuild of my site (event when there is no new commits to the repo) and, because of the date Nikola will publish automatically the new scheduled post.

Yes, I can have dynamism in my static site!

This means:

  1. I can schedule posts in the future (meaning I can write 4 articles in a week and publish them once a week at the right time. This is good for me because I often write in batches or spurts of energy, interests and time).

  2. I can have a Zap (in Zapier) or a Flow (in ActionPieces) that will trigger a rebuild of my site every day at 10:00, so I can have a new post published every day at 10:00 (or 10:05, depending on the speed of the rebuild).

I will get into more detail about this in a future post.

Step-by-Step Guide to Deploying on Cloudflare Pages

Step 1: Setting Up Your Environment

A Pipfile is essential for deploying on Cloudflare Pages, as it manages your Python dependencies.

This file’s contents will depend on the specific configurations and input formats of your Nikola site, such as Markdown, Asciidoc, or reST.

The Pipfile is used by the Pipenv tool, which is used to manage Python dependencies and virtual environments.

In this article I write also about a Gemfile, which is used by the Bundler tool, which is used to manage Ruby dependencies and virtual environments. I added this because I use asciidoctor (Ruby-based) to process my Asciidoc files.
Both files (Pipfile and Gemfile) have to be in the root of your repository.

Sample Pipfile

This sample Pipfile includes the dependencies for a Nikola site using Markdown and Asciidoc. You may update the versions as needed.

url = ''
verify_ssl = true
name = 'pypi'

python_version = '3.7'

Nikola = '8.2.2'
markdown = '3.3'
asciidoc = '10.2.0'
pygments = '2.13.0'
jinja2 = '3.1.2'

Configuring Asciidoc in Nikola (optional)

Configuring Asciidoc in Nikola involves specifying the binary path and options in the file.

In this case I want to use asciidoctor as the binary and I want to have a table of contents and use Font Awesome icons when processing the file.

ASCIIDOC_BINARY = "asciidoctor"

# Specify options to the asciidoc compiler (as a string).
ASCIIDOC_OPTIONS = "-a toc -a icons=font -a icon-set=fa"
Sample Gemfile

For Nikola sites using Asciidoc, a Gemfile is also required to ensure proper processing of Asciidoc files.

source ''
gem 'asciidoctor'
  1. Sign in to Cloudflare Pages.

  2. Choose 'Workers and Pages' from the left sidebar.

  3. Click the tab 'Pages'.

  4. Clock "Connect to Git" to connect your GitHub or GitLab account.

  5. Select the repository containing your Nikola site.

  6. Configure the build settings as per your project’s needs.

And that’s it!

Happy deploying!


Magic The Gathering Made Easy: Adapting MTG to be Kid-Friendly for My 6-Year-Old Daughter


I enjoy playing Magic The Gathering (MTG) and my 6-year-old daughter wanted to play with me. The problem? She can not yet read the cards, and she does not understand all the rules. So what did I do? I adapted the rules to make it easier for her to play.

What is MTG (Magic The Gathering)?

It is a card game where you are a wizard, and you cast spells to defeat your opponent. You and your opponent(s) have 20 life points each, and you have to deal damage so that their life reaches 0. You have different kinds of spells, and you can summon creatures to help you. Each spell has its own rules and properties. There are several species and types of creatures, and each one has its own abilities. You can mix and match your cards as you see fit, and you can create your own deck. There are also different kinds of land. Each land gives you MANA (energy to cast spells), and you can only cast spells if you have enough MANA and of the right kind. Each kind has its own properties:

  • Forests (green) is the color of nature. It is the color of growth, life, and brute force. Usually associated with elves, druids, and beasts, the play style is slower than the other colors, but it is powerful.
  • Mountains (red) is the color of chaos, fire, and destruction. Usually associated with goblins, dragons, and barbarians, the play style is fast and aggressive.
  • Islands (blue) is the color of knowledge, illusion, and trickery. Generally associated with wizards, merfolks, and sphinxes, the play style is slow and defensive, with ways to interrupt the game of the opponent.
  • Plains (white) is the color of order, law, and protection. Usually associated with angels, knights, and clerics, the play style is slow and defensive, with ways to earn more life points.
  • Swamps (black) is the color of death, decay, and ambition. Commonly associated with zombies, vampires, and demons, the play style is fast and aggressive, with ways to deal damage to the opponent and to destroy their creatures.

There are many ways to play MTG (formats), and the most common is the Standard format.

I used to play a lot around 20 years ago, and I recently started playing again, but it seems all the rules have been changed and many new formats have appeared. There are now restrictions on the kind of cards you can play, and the game duration has been reduced. The formats that are most similar to the ones I used to play are Legacy and Vintage.

I won't be learning all the new rules and formats, so I decided to go with the ones I already knew.

For the purist, please note that I am not following the official rules.

How to play

I decided to adapt the rules I know to make it easier for her to play.

1. The deck

You may have between 40 and 75 cards in your deck. I decided to go with one-color-decks as it is easier to understand.

I explained to her the different kinds of lands and game styles, and she decided to go with a red deck and chose a green deck for me. I helped her build a deck with 60 cards, with a maximum 4 copies of each card. I also asked her to have at least 20 lands. She also gets to call the creatures whatever she wants. (She has a creature called "Filigree Familiar" which is a 2/2 creature she calls "Little Fox".)

We removed all non-creature cards as they make the game more complex.

We "removed" all the abilities of the creatures, as she does not understand them yet. (I will add them later when she learns how to read). When I mean "removed their abilities" I really mean "ignored their abilities".

2. The game - The rules

  1. Each player shuffles their deck and draws 7 cards. She has to have at least 2 lands. If not, she re-draws 7 cards again.
  2. She decides who starts. The one that starts does not draw a card on the first turn.
  3. Each player draws a card at the beginning of their turn.
  4. Each player can play (put on the table) one land per turn.
  5. Each player can play as many creatures as they want per turn, as long as they have enough MANA.
  6. Each player can attack with their creatures. The creatures can attack the other player or the other players creatures. The other player can block the attack with their creatures. If a creature attacks, it cannot block.
  7. All creatures suffer damage at the end of the turn. If a creature has damage equal or greater than its life (defense), it goes to the rest-deck for it to rest (sleep) until the next game. (this would the graveyard and the creatures usually die, but I found out that she does not like the idea of killing the creatures)
  8. The game ends when one of the players has 0 magic (life) points. Again, she doesn't like the idea of death, so we use "magic points" instead of "life points". As with the creatures, after sleeping for a while, the magic points are restored. This is easier to understand as the creatures also sleep.
  9. All creatures suffer invocation sickness the first turn they are on the table. That means they cannot attack (or use their abilities) the first turn they are on the table.
  10. Each turn has the following phases:

    1. Untap: all the cards are untapped (turned 90 degrees to the right). This is the first phase of the turn.
    2. Draw: the player draws a card.
    3. Main: the player can play lands and creatures by tapping the required lands.
    4. Combat: the player can attack with their creatures.
    5. Defense: the opponent can block the attack with their creatures and damage is calculated.
    6. End: the player passes the turn to the opponent.

This continues until one of the players has 0 magic (life) points.

3. The cards

How do we use the cards?

Each card has a cost in MANA (energy) and a cost in lands. The cost of land is the number besides the symbol of the land. The cost in MANA is the number in the top-right corner and is the sum of both the symbol plus the number.

For example, a card with a cost of 2R (Red) costs 2 MANA and 1 mountain.

Let's take for example, Chandra's Magmutt.

  • (1) Required MANA of type "Mountain"
  • (2) Required MANA of any type
  • (3) Total defense (total damage points it can take before it dies)
  • (4) Total attack (total damage points it can deal)
  • (5) Card color (red)

These are the only parts of the card we use. The rest is ignored.

4. Game layout

With these rules the game layout looks like this

5. Additional comments

  • My daughter does not like the idea of killing the creatures, so we send them to the sleep-zone instead of the graveyard. (I will change this when she is older)
  • We use magic points instead of life points for the same reason as above. It is also easier to understand.
  • She likes to take her own decisions, so I give her some hints as to what would happen if she does something. For example, I tell her that if she attacks with a creature, it will go to sleep (die) if it attacks a creature with more attack points than its own defense. She then decides if she wants to attack or not.

And that's it! She can now play MTG with me, and she is having fun.

All in all, I think the changes are not so drastic and that allows me to introduce new rules (the real rules) as she grows up. Abilities are the next step, and then we can start using non-creature cards. But all when she learns how to read.

I hope these rules also help you play with your kids. If you have any suggestions, please let me know in the comments.

How to change docker root data directory and why would you want to do that (hint: to optimize space)


I have a small vps for some personal projects which has 20 gb storage. I have one project there, and a few day ago I no longer had any available space. That meant docker services went down (and so the small project). I knew the project should not use that much space, and I found out that docker was using around 10gb space for overlay2.

The whole overlay2 situation is enough for another post, but I found out (after researching and reading a lot of articles) that it grows pretty fast, and it is really hard to clean. òverlay2 is one of the ways docker synchronizes the filesystem, and it duplicates data.

I decided to change the root data directory (by default at /var/lib/docker) to another volume attached to my vps, which I can increase in space if needed.



Make a backup of all your information (volumes, containers and everything that you cannot automatically generate again.)

1. Stop docker service

sudo systemctl stop docker

on older systems

sudo service docker stop

2. Edit etc/docker/daemon.json or create it if it does not exist

nano /etc/docker/daemon.json

Add the following line if empty

   "data-root": "/path/to/your/new/docker/root"

or, if there is already something there, add just the key, appending a comma in the previous line

"data-root": "/path/to/your/new/docker/root"

so that is looks like this:

  "another-key": "another value", 
  "data-root": "/path_to_new_root/docker"


  • This will change your data directory, not move it. Your data will not be there when you restart the docker service. All the containers and volumen will be created from zero.
  • This will recreate the whole docker data directory structure on the destination, as docker need it to run properly.
  • Doing this is similar to removing all your containers, volumes and so on. (although in this case they are still on the old directory until you remove them manually)
  • If you use a volume, another hard-drive or similar as the new destination, make sure it has enough free space available. I would recommend no less than 10 gb for small projects, with the possibility of increasing it.

3. Restart docker

sudo systemctl restart docker

or, on older systems

sudo service docker start

4. Rebuild your projects and restore backups if necessary

If you use docker-compose for your projects, just run docker compose up -d --build.

If you have database and data backups, restore them.

With this you have now changed the root data directory from /var/lib/docker to /path_to_new_root/docker


How to configure an Ubuntu Linux server to allow SSH sessions only with a key and disable password-based


I have a server running Ubuntu 22.04 LTS which I use for some personal projects and I wanted to make it more secure by only allowing SSH sessions with a key and disabling password-based authentication.

What is an SSH key and why is it more secure?

SSH keys are a pair of cryptographic keys which are used to authenticate to an SSH server. When you generate the key, 2 files are created. There is a private key (kept in the client) and a public key .pub (added to the server). The private key is used to encrypt the data and the public key is used to decrypt it.

Steps to configure the server

1. Create an SSH Key Pair (if you don't have one)

On your local machine, run the following command to generate a new SSH key pair. (You can use the default values)

ssh-keygen -t rsa -b 4096 -C "[email protected]"


  • The email is used as a label for the key. You can use any email you want.
  • If you want additional security, add a passphrase to the key. (You will need to enter the passphrase each time you use the key). -- There are different views on whether this is a good idea or not. I think it is a good idea, but it is up to you. -- You can skip this step by pressing enter twice.
  • The default key name is id_rsa. You can use a different name if you want.
  • The default location is ~/.ssh. You can use a different location if you want.
  • The default permissions are 600 for the private key. (I have a quick-note about permissions at (Quick-note) SSH Keys Permissions

2. Copy the public key to the server

ssh-copy-id <username>@<server_ip>

If you have more than one key (identity), you can specify the key to use with the -i flag. (The default is ~/. ssh/


You can also add the public key to the server manually. (This is useful if you don't have ssh-copy-id installed)

cat ~/.ssh/ | ssh <username>@<server_ip> "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

or just copy the contents of the public key .pub and paste it in the ~/.ssh/authorized_keys file on the server.

ssh-copy-id -i ~/.ssh/ <username>@<server_ip>

3. Test the configuration

Check if you can access the server with the key. If you are using the default key, you don't need to specify it.

ssh <username>@<server_ip>

If you are using a different key, you need to specify it with the -i flag.

ssh -i ~/.ssh/<key_name> <username>@<server_ip>

If you can access the server, you can continue with the next steps. If not, check the logs in /var/log/auth.log to find out what is wrong. (You can use tail -f /var/log/auth.log to see the logs in real time)

4. Configure the server to only allow SSH sessions with a key and disable password-based authentication

Edit the /etc/ssh/sshd_config file:

sudo nano /etc/ssh/sshd_config

And add or edit the following line:

PasswordAuthentication no

5. Restart the SSH service

sudo systemctl restart ssh

or, if you are using an older version of Ubuntu

sudo service ssh restart

You have now configured your server to allow ssh sessions only with a key 😁