<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Julián Mulet</title>
    <description>The latest articles on DEV Community by Julián Mulet (@uxtechie).</description>
    <link>https://dev.to/uxtechie</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F678491%2F8bd1d460-ad65-49f3-b1a4-164da9b49e83.png</url>
      <title>DEV Community: Julián Mulet</title>
      <link>https://dev.to/uxtechie</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/uxtechie"/>
    <language>en</language>
    <item>
      <title>ZSH, tu shell DevOps en Ubuntu y Windows Subsystem for Linux</title>
      <dc:creator>Julián Mulet</dc:creator>
      <pubDate>Thu, 18 May 2023 05:58:08 +0000</pubDate>
      <link>https://dev.to/uxtechie/zsh-tu-shell-devops-en-ubuntu-y-windows-subsystem-for-linux-5h2k</link>
      <guid>https://dev.to/uxtechie/zsh-tu-shell-devops-en-ubuntu-y-windows-subsystem-for-linux-5h2k</guid>
      <description>&lt;p&gt;&lt;sup&gt;&lt;em&gt;Basado en este articulo: &lt;a href="https://drasite.com/blog/Pimp%20my%20terminal" rel="noopener noreferrer"&gt;Fuente DRA&lt;/a&gt;.&lt;/em&gt;&lt;/sup&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introducción
&lt;/h2&gt;

&lt;p&gt;El &lt;strong&gt;software libre&lt;/strong&gt; hace tiempo que se ha convertido en &lt;strong&gt;la mejor opción&lt;/strong&gt; para crear servicios y aplicaciones.&lt;/p&gt;

&lt;p&gt;Este es el motivo por el cual muchos utilizamos la &lt;strong&gt;consola de Linux&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Si además tienes el perfil &lt;strong&gt;DevOps&lt;/strong&gt;, usarás tanto herramientas de &lt;strong&gt;desarrollador&lt;/strong&gt;: &lt;code&gt;git&lt;/code&gt;, &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;pip&lt;/code&gt;, etc. como otras más propias de &lt;strong&gt;sysadmin&lt;/strong&gt;: &lt;code&gt;docker&lt;/code&gt;, &lt;code&gt;kubectl&lt;/code&gt;, &lt;code&gt;systemctl&lt;/code&gt;, &lt;code&gt;ssh&lt;/code&gt;, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Las CLI más habituales
&lt;/h3&gt;

&lt;p&gt;&lt;sup&gt;&lt;em&gt;&lt;strong&gt;NOTA:&lt;/strong&gt; No pretendo que esta sea una lista cerrada que cubra todos los casos pero son algunas de las más habituales hoy en día.&lt;/em&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;git&lt;/code&gt;: control de versiones.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm&lt;/code&gt;: gestor de paquetes &lt;strong&gt;Node.js&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;yarn&lt;/code&gt;: gestor de paquetes &lt;strong&gt;Node.js&lt;/strong&gt; alternativo muy popular.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nvm&lt;/code&gt;: gestor de entornos virtuales de &lt;strong&gt;Node.js&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pip&lt;/code&gt;: gestor de paquetes de &lt;strong&gt;Python&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker&lt;/code&gt;: gestor de &lt;strong&gt;contenedores&lt;/strong&gt; e imágenes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker-compose&lt;/code&gt;: gestor de &lt;strong&gt;manifiestos&lt;/strong&gt; de &lt;strong&gt;Docker&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl&lt;/code&gt;: consola de &lt;strong&gt;Kubernetes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;helm&lt;/code&gt;: gestor de despliegue de aplicaciones de &lt;strong&gt;Kubernetes&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ZSH, tu asistente personal
&lt;/h2&gt;

&lt;p&gt;Manejar todo esto es complejo y aquí es donde entra &lt;strong&gt;zsh&lt;/strong&gt;, un shell personalizable con infinidad de plugins.&lt;/p&gt;

&lt;p&gt;Esta es una receta que &lt;strong&gt;se puede adaptar fácilmente a las necesidades de cada uno&lt;/strong&gt; y al final del post encontrarás los links para que puedas explorar esta posibilidad.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ayudas visuales
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Carpeta actual&lt;/strong&gt; y &lt;strong&gt;estado del repositorio git&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hb1ezmm1qwf2wb5hzmc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hb1ezmm1qwf2wb5hzmc.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tiempo y estado de ejecución&lt;/strong&gt; del comando anterior:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82kfot00gzbd3srrelua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82kfot00gzbd3srrelua.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Colores&lt;/strong&gt; que mejoran la legibilidad:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwkssh0xy94qpp60wpzrr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwkssh0xy94qpp60wpzrr.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcq4guxgs38kg7qoiddo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcq4guxgs38kg7qoiddo.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdp0ocz9sk9icbdq9almq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdp0ocz9sk9icbdq9almq.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Otras ayudas
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Autocompletado&lt;/strong&gt; de comandos:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlxhe76hldvspfb9a3fl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlxhe76hldvspfb9a3fl.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copiar &lt;strong&gt;contenido de un fichero al portapapeles&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxepmgei6abc59mpmhzu4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxepmgei6abc59mpmhzu4.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comandos recursivos&lt;/strong&gt; utilizando el doble operador &lt;code&gt;**&lt;/code&gt;:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc241v47xnj1jhahtxb2z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc241v47xnj1jhahtxb2z.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Búsqueda dentro del historial de comandos&lt;/strong&gt; introduciendo los primeros caracteres y usando los cursores &lt;code&gt;↑&lt;/code&gt; &lt;code&gt;↓&lt;/code&gt; &lt;code&gt;→&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fko65fbylb9sbyi9f6317.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fko65fbylb9sbyi9f6317.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Instalación
&lt;/h2&gt;

&lt;p&gt;Lo primero que haremos es instalar en el sistema la fuente &lt;strong&gt;Nerd Font FiraCode&lt;/strong&gt; por ser compatible con &lt;strong&gt;vscode&lt;/strong&gt;, &lt;a href="https://github.com/ryanoasis/nerd-fonts/issues/332" rel="noopener noreferrer"&gt;related issue&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--depth&lt;/span&gt; 1 https://github.com/ryanoasis/nerd-fonts.git /tmp/nerd-fonts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;
  &lt;strong&gt;sólo para Windows:&lt;/strong&gt; &lt;em&gt;Pincha para ver.&lt;/em&gt;
  &lt;p&gt;Seguimos con la instalación de la fuente, abre la consola &lt;strong&gt;Powershell como administrador&lt;/strong&gt; e introduce estos comandos:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# excluir la seguridad de WSL Ubuntu&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;powershell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ExecutionPolicy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Bypass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\excludeWSL.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;powershell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ExecutionPolicy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Bypass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;\tmp\nerd-fonts\install.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FiraCode&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-ExecutionPolicy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Default&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;\tmp\nerd-fonts\&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Ahora instala el &lt;strong&gt;soporte para las notificaciones&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Install-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BurntToast&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;sólo para Linux:&lt;/strong&gt; &lt;em&gt;Pincha para ver.&lt;/em&gt;
  &lt;p&gt;Seguimos con la instalación de la fuente, abre la consola e introduce este comando:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/tmp/nerd-fonts/install.sh FiraCode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Ahora instala el &lt;strong&gt;soporte para copiar al portapapeles&lt;/strong&gt; desde el cli:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; xclip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Y continuamos con el terminal &lt;strong&gt;kitty&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;kitty
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Ábrelo y pulsa &lt;code&gt;ctrl+shift+f2&lt;/code&gt; para &lt;strong&gt;generar el fichero de configuración&lt;/strong&gt; y por último &lt;strong&gt;cambia el tema de color&lt;/strong&gt; con este comando:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;wget &lt;span class="nt"&gt;-qO-&lt;/span&gt; https://raw.githubusercontent.com/Mayccoll/Gogh/master/themes/symphonic.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;/p&gt;

&lt;p&gt;Instalar dependencias&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;python-is-python3
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;python3-pip
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;powerline
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;zsh
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;zplug
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;fzf
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;imagemagick
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;grc
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;bat
&lt;span class="nb"&gt;sudo &lt;/span&gt;snap &lt;span class="nb"&gt;install &lt;/span&gt;lsd
&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; pip3 &lt;span class="nb"&gt;install &lt;/span&gt;Pygments
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;which zsh&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; chsh &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;which zsh&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  notify-send
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://codelearn.me/2019/01/13/wsl-windows-toast.html" rel="noopener noreferrer"&gt;https://codelearn.me/2019/01/13/wsl-windows-toast.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mi repo dotfiles:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/uxtechie" rel="noopener noreferrer"&gt;
        uxtechie
      &lt;/a&gt; / &lt;a href="https://github.com/uxtechie/dotfiles" rel="noopener noreferrer"&gt;
        dotfiles
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      ~/.dotfiles
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Recursos de personalización
&lt;/h2&gt;

&lt;p&gt;Aquí encontrarás información para personalizar tu shell.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nerdfonts.com/font-downloads" rel="noopener noreferrer"&gt;Más fuentes &lt;strong&gt;Nerd Fonts&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nerdfonts.com/cheat-sheet" rel="noopener noreferrer"&gt;Iconos de la fuente Nerd Font&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sw.kovidgoyal.net/kitty/conf/" rel="noopener noreferrer"&gt;Terminal &lt;strong&gt;kitty&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mayccoll.github.io/Gogh/" rel="noopener noreferrer"&gt;Temas de color para el terminal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/garabik/grc" rel="noopener noreferrer"&gt;Añade color a comandos genéricos con &lt;strong&gt;grc&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Peltoche/lsd" rel="noopener noreferrer"&gt;Sustituto de &lt;code&gt;ls&lt;/code&gt; &lt;strong&gt;lsd&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/sharkdp/bat" rel="noopener noreferrer"&gt;Sustituto de &lt;code&gt;cat&lt;/code&gt; &lt;strong&gt;bat&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/aristocratos/bpytop" rel="noopener noreferrer"&gt;Sustituto de &lt;code&gt;top&lt;/code&gt; &lt;strong&gt;Bpytop&lt;/strong&gt;&lt;/a&gt;, para cambiar el tema de color pulsa &lt;code&gt;shift+m&lt;/code&gt; y elige &lt;em&gt;flat-remix&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>bash</category>
      <category>ubuntu</category>
      <category>spanish</category>
      <category>devops</category>
    </item>
    <item>
      <title>Scalable architectures / Project management, tip 1: use NX as monorepo manager</title>
      <dc:creator>Julián Mulet</dc:creator>
      <pubDate>Thu, 05 Jan 2023 18:51:49 +0000</pubDate>
      <link>https://dev.to/uxtechie/nx-gist-create-a-vite-react-typescript-monorepo-quickly-2a3h</link>
      <guid>https://dev.to/uxtechie/nx-gist-create-a-vite-react-typescript-monorepo-quickly-2a3h</guid>
      <description>&lt;p&gt;&lt;small&gt;Cover attribution: &lt;a href="https://www.pexels.com/photo/a-champagne-bottle-against-a-light-pink-background-5379748/" rel="noopener noreferrer"&gt;Leeloo Thefirst&lt;/a&gt; &lt;small&gt;&lt;/small&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Generating and keeping the scaffolding of a Web application updated is one of the most complex tasks I have ever faced managing a project.&lt;/p&gt;

&lt;p&gt;I won't go into the details of why I ended up choosing &lt;a href="https://nx.dev/" rel="noopener noreferrer"&gt;NX&lt;/a&gt; over &lt;a href="https://lerna.js.org/" rel="noopener noreferrer"&gt;Lerna&lt;/a&gt;, &lt;a href="https://turbo.build/repo" rel="noopener noreferrer"&gt;Turborepo&lt;/a&gt; and even &lt;a href="https://bit.dev/" rel="noopener noreferrer"&gt;Bit&lt;/a&gt; for this task. Here I should clarify that the case of Bit is somewhat different because it manages each component as a separate library.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why NX?
&lt;/h2&gt;

&lt;p&gt;I will simply show the power of NX with a simple example.&lt;/p&gt;

&lt;p&gt;Create a Vite, React, Typescript monorepo quickly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# NOTE: this gist uses pnpm as Node package manager&lt;/span&gt;
&lt;span class="c"&gt;# and the next command alias is needed to work as&lt;/span&gt;
&lt;span class="c"&gt;# expected:&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;pnx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"pnpm nx"&lt;/span&gt;

&lt;span class="c"&gt;# CREATE a new MONOREPO (Typescript, Github CI, pnpm):&lt;/span&gt;

&lt;span class="c"&gt;# OPTION 1, FRAMEWORK preset type:&lt;/span&gt;
npx create-nx-workspace@latest @yourTeamId &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ci&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;github &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cli&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nx &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--nxCloud&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--packageManager&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pnpm &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--preset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ts

&lt;span class="c"&gt;# OPTION 2, APP preset type:&lt;/span&gt;
npx create-nx-workspace@latest @yourTeamId &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ci&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;github &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cli&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nx &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--nxCloud&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--packageManager&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pnpm &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--preset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;apps

&lt;span class="c"&gt;# ---&lt;/span&gt;

&lt;span class="c"&gt;# ADD a new LIB to previous created monorepo (Vite, &lt;/span&gt;
&lt;span class="c"&gt;# SWC, Vitest):&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; @yourTeamId
pnpm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; @nrwl/js

&lt;span class="c"&gt;# OPTION 1, WEB lib:&lt;/span&gt;
pnx g @nrwl/js:lib myWebLib &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--importPath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@yourTeamId/myWebLib &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bundler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vite &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--compiler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;swc &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--unitTestRunner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vitest &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--publishable&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--includeBabelRc&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;:lib 

&lt;span class="c"&gt;# OPTION 2, NODE lib:&lt;/span&gt;
pnx g @nrwl/js:lib myLib &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--importPath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@yourTeamId/myLib &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bundler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vite &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--compiler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;swc &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--unitTestRunner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vitest &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--publishable&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--testEnvironment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;node &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;:lib 

&lt;span class="c"&gt;# ---&lt;/span&gt;

&lt;span class="c"&gt;# ADD a new APP to monorepo (React, Vite, SWC,&lt;/span&gt;
&lt;span class="c"&gt;# Vitest):&lt;/span&gt;
pnpm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; @nrwl/react
pnx g @nrwl/react:application myApp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--importPath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@yourTeamId/myApp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bundler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vite &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--compiler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;swc &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--unitTestRunner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vitest &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--routing&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;:app

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works as expected? Try it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# BUILD and run all TESTS&lt;/span&gt;
pnx run-many &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="c"&gt;# START app in DEV mode&lt;/span&gt;
pnx run myApp:serve

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;And of course this is just a simple example.&lt;/p&gt;

&lt;p&gt;With NX you can publish libraries as npm packages, &lt;code&gt;pnx run myLib:publish&lt;/code&gt;, and its ease of use invites you to create new libraries more frequently.&lt;/p&gt;

&lt;p&gt;This last feature is what really makes your project scalable 😉.&lt;/p&gt;




&lt;h2&gt;
  
  
  Create your own NX Plugin
&lt;/h2&gt;

&lt;p&gt;It even allows us to create custom plugins to create a scaffolding tailored to your needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ADD a new NX PLUGIN to monorepo (SWC):&lt;/span&gt;
pnpm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; @nrwl/nx-plugin
pnx g @nrwl/nx-plugin:plugin yourPluginName &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--importPath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;@yourTeamId/yourPluginName &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--compiler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;swc &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;:plugin

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;If you give it a chance it is likely to become a rewarding tool in your day to day life.&lt;/p&gt;

&lt;p&gt;Thanks for reading me 😄.&lt;/p&gt;

&lt;p&gt;Challenge: Why am I using tags when creating libraries and applications?&lt;/p&gt;

&lt;p&gt;I look forward to your answer...&lt;/p&gt;

</description>
      <category>watercooler</category>
      <category>career</category>
      <category>mentalhealth</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Scalable architectures / Code management, tip 1: imperative vs declarative</title>
      <dc:creator>Julián Mulet</dc:creator>
      <pubDate>Sat, 17 Dec 2022 19:37:01 +0000</pubDate>
      <link>https://dev.to/uxtechie/scalable-architectures-code-management-tip-1-imperative-vs-declarative-3k30</link>
      <guid>https://dev.to/uxtechie/scalable-architectures-code-management-tip-1-imperative-vs-declarative-3k30</guid>
      <description>&lt;p&gt;&lt;small&gt;Cover attribution: &lt;a href="https://unsplash.com/@namroud?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Namroud Gorguis&lt;/a&gt; en &lt;a href="https://unsplash.com/es/s/fotos/computer-cassette?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;small&gt;&lt;/small&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Programming techniques and languages have evolved to make reading more intuitive for people, moving from a more &lt;strong&gt;#imperative&lt;/strong&gt; approach, focused on &lt;strong&gt;how the task is processed&lt;/strong&gt;, to a more &lt;strong&gt;#declarative&lt;/strong&gt; one, focused on &lt;strong&gt;what is being processed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This evolution is constantly changing&lt;/strong&gt; and, therefore, it happens that what 20 years ago was considered declarative today is likely to fall more in the category of imperative.&lt;/p&gt;

&lt;p&gt;In this article you can see two examples of this transformation. The first case starts from the &lt;strong&gt;#assembly&lt;/strong&gt; language of a &lt;em&gt;CPU&lt;/em&gt; and the second case from the &lt;strong&gt;#css&lt;/strong&gt; &lt;em&gt;markup language&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Evolution of general purpose languages
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The for loop
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// for-loop.asm&lt;/span&gt;

&lt;span class="c1"&gt;// source:&lt;/span&gt;
&lt;span class="c1"&gt;// https://eclecticlight.co/2021/06/29/code-in-arm-assembly-conditional-loops/&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// here an imperative example of a classic for-loop&lt;/span&gt;
&lt;span class="c1"&gt;// written in ARM assembler code&lt;/span&gt;

&lt;span class="c1"&gt;// and the maximum index in X4:&lt;/span&gt;
&lt;span class="nc"&gt;MOV&lt;/span&gt; &lt;span class="nc"&gt;X5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;// start index = 1&lt;/span&gt;
&lt;span class="nc"&gt;MOV&lt;/span&gt; &lt;span class="nc"&gt;X4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="c1"&gt;// end index = 5&lt;/span&gt;
&lt;span class="n"&gt;for_loop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;// do_something&lt;/span&gt;
&lt;span class="nc"&gt;ADD&lt;/span&gt; &lt;span class="nc"&gt;X5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;X5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;// increment the index by 1&lt;/span&gt;
&lt;span class="nc"&gt;CMP&lt;/span&gt; &lt;span class="nc"&gt;X5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;X4&lt;/span&gt; &lt;span class="c1"&gt;// check whether end index has been reached&lt;/span&gt;
&lt;span class="nc"&gt;B&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LE&lt;/span&gt; &lt;span class="n"&gt;for_loop&lt;/span&gt; &lt;span class="c1"&gt;// if index &amp;lt;= end index, loop back&lt;/span&gt;
&lt;span class="c1"&gt;// next code after loop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
* for-loop.c
*
* here you can show the declarative version of previous 
* assembler example, nowadays this language C implementation
* is an imperative example:
*/&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#define ARRAY_LENGTH(array_var) (sizeof(array_var) / sizeof((array_var)[0]))
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;number_collection&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;collection_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ARRAY_LENGTH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number_collection&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;collection_length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;do_something_with_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number_collection&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// for-loop.js&lt;/span&gt;

&lt;span class="c1"&gt;// here a declarative modern functional version of a&lt;/span&gt;
&lt;span class="c1"&gt;// ECMAScript 6 loop&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;miscCollection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;miscCollection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;itemInCollection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;doSomethingWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;itemInCollection&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Evolution of CSS markup language
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The abstraction layer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/*
* auto-layout.css
*
* Auto layout, imperative legacy css
*/&lt;/span&gt;

&lt;span class="nc"&gt;.horizontal-center-center&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.horizontal-right-center&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex-end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.vertical-bottom-center&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex-end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
* auto-layout.scss
*
* Auto layout, more declarative version because of
* use of semantic scss mixins
*/&lt;/span&gt;

&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;auto-layout-base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;auto-layout-horizontal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;auto-layout-base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;auto-layout-vertical&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;auto-layout-base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.horizontal-center-center&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;auto-layout-horizontal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.horizontal-right-center&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;auto-layout-horizontal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex-end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.vertical-bottom-center&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;auto-layout-vertical&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex-end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
* auto-layout.css.ts
*
* full semantic vanilla-extract version
* https://vanilla-extract.style/
*/&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mixVariants&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@Utils/styles/mix-variants.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StyleRule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;styleVariants&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@vanilla-extract/css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StyleRule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;horizontal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StyleRule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;flexDirection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;row&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vertical&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StyleRule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;flexDirection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;column&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;horizontalVariants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styleVariants&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;horizontal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;horizontal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex-end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;horizontalAlignVariants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styleVariants&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;verticalVariants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styleVariants&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;vertical&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex-end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;verticalAlignVariants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styleVariants&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;autoLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;horizontal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mixVariants&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;horizontalVariants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;horizontalAlignVariants&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mixVariants&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;horizontalVariants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;horizontalAlignVariants&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;vertical&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mixVariants&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;verticalVariants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;verticalAlignVariants&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;








&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AutoLayoutDemo.jsx&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// This auto layout demo show examples of how to&lt;/span&gt;
&lt;span class="c1"&gt;// consume all above different style types&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;legacyStyles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./auto-layout-legacy.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;scssStyles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./auto-layout.scss&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;autoLayout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./auto-layout.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AutoLayoutDemo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;other&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;section&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;legacyStyles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;horizontal-center-center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Horizontal&lt;/span&gt; &lt;span class="nx"&gt;Center&lt;/span&gt; &lt;span class="nx"&gt;Center&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/section&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;section&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;scssStyles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;horizontal-right-center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Horizontal&lt;/span&gt; &lt;span class="nx"&gt;Right&lt;/span&gt; &lt;span class="nx"&gt;Center&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/section&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* 
        finally, the bellow example use the vanilla-extract
        compiled css resources. Vanilla-extract is not a 
        runtime performance penalty tool like styled-components
        or other similar inline styles tools
       */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;section&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;autoLayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertical&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;center&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Vertical&lt;/span&gt; &lt;span class="nx"&gt;Bottom&lt;/span&gt; &lt;span class="nx"&gt;Center&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/section&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/article&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Thank you for taking the time to read and share your thoughts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://es.linkedin.com/in/julianmulet?trk=profile-badge"&gt;Julián Mulet&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>programming</category>
      <category>cleancode</category>
      <category>scs</category>
    </item>
    <item>
      <title>¿Son las configuraciones RAID clásicas compatibles con las unidades SSD?</title>
      <dc:creator>Julián Mulet</dc:creator>
      <pubDate>Mon, 04 Oct 2021 12:48:59 +0000</pubDate>
      <link>https://dev.to/uxtechie/son-las-configuraciones-raid-clasicas-compatibles-con-las-unidades-ssd-5061</link>
      <guid>https://dev.to/uxtechie/son-las-configuraciones-raid-clasicas-compatibles-con-las-unidades-ssd-5061</guid>
      <description>&lt;p&gt;&lt;sup&gt;&lt;em&gt;Cover image attribution: &lt;a href="https://commons.wikimedia.org/wiki/File:Adaptec_8885_SAS_RAID_controller_(SFF-8643_and_SFF-8644_connectors).png"&gt;Dmitry Nosachev&lt;/a&gt;, &lt;a href="https://creativecommons.org/licenses/by-sa/4.0"&gt;CC BY-SA 4.0&lt;/a&gt;, via Wikimedia Commons.&lt;/em&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducción
&lt;/h2&gt;

&lt;p&gt;Las unidades de almacenamiento &lt;strong&gt;HDD&lt;/strong&gt; en &lt;strong&gt;entornos profesionales&lt;/strong&gt; son gestionadas en configuraciones &lt;strong&gt;RAID&lt;/strong&gt; por motivos de &lt;strong&gt;alta disponibilidad&lt;/strong&gt; y &lt;strong&gt;rendimiento&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;¿Sigue siendo válida esta técnica si usamos unidades &lt;strong&gt;SSD&lt;/strong&gt;? Vamos a verlo.&lt;/p&gt;

&lt;h2&gt;
  
  
  RAID: Redundant Array of Independent Disks
&lt;/h2&gt;

&lt;p&gt;Un sistema &lt;strong&gt;RAID&lt;/strong&gt; forma una &lt;strong&gt;matriz distribuyendo los datos&lt;/strong&gt; entre los distintos discos.&lt;/p&gt;

&lt;p&gt;Podemos elegir entre varias configuraciones &lt;strong&gt;RAID&lt;/strong&gt; en cuyos &lt;strong&gt;extremos&lt;/strong&gt; están el &lt;strong&gt;RAID 0&lt;/strong&gt; y el &lt;strong&gt;RAID 1&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;El &lt;strong&gt;RAID 0&lt;/strong&gt; no ofrece protección por lo que estaríamos realmente ante un &lt;strong&gt;no RAID&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Funciona &lt;strong&gt;sumando la capacidad de los discos y accediendo de forma simultánea&lt;/strong&gt; a ellos. Obviamente ofrece &lt;strong&gt;mayor rendimiento&lt;/strong&gt; pero &lt;strong&gt;la unidad fallará si falla cualquier disco&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TPgoqCoU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://upload.wikimedia.org/wikipedia/commons/thumb/1/19/Raid0.png/220px-Raid0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TPgoqCoU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://upload.wikimedia.org/wikipedia/commons/thumb/1/19/Raid0.png/220px-Raid0.png" alt="Diagrama de distribución de datos en RAID 0" width="220" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¿Y el &lt;strong&gt;RAID 1&lt;/strong&gt;? pues es justo lo contrario, &lt;strong&gt;en todos los discos se escribe la misma información&lt;/strong&gt; y &lt;strong&gt;mientras quede un disco&lt;/strong&gt; operativo &lt;strong&gt;la unidad seguirá operativa&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4bfaCISr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://upload.wikimedia.org/wikipedia/commons/thumb/e/e2/Raid1.png/220px-Raid1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4bfaCISr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://upload.wikimedia.org/wikipedia/commons/thumb/e/e2/Raid1.png/220px-Raid1.png" alt="Diagrama de distribución de datos en RAID 1" width="220" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pero ¿realmente la &lt;strong&gt;diferencia en fiabilidad&lt;/strong&gt; es tan importante? ¿No es el hardware suficientemente fiable? Vamos a verlo en &lt;strong&gt;probabilidad de pérdida de datos&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;RAID Level&lt;/th&gt;
&lt;th&gt;Año 1&lt;/th&gt;
&lt;th&gt;Año 2&lt;/th&gt;
&lt;th&gt;Año 3&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RAID 0&lt;/td&gt;
&lt;td&gt;2,8 %&lt;/td&gt;
&lt;td&gt;5,7 %&lt;/td&gt;
&lt;td&gt;8,4 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAID 1&lt;/td&gt;
&lt;td&gt;0,00004 %&lt;/td&gt;
&lt;td&gt;0,00009 %&lt;/td&gt;
&lt;td&gt;0,00013 %&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;NOTA:&lt;/strong&gt; estas cifras están extraídas de esta &lt;a href="https://www.servethehome.com/raid-calculator/raid-reliability-calculator-simple-mttdl-model/"&gt;web que usa el modelo &lt;strong&gt;MTTDL&lt;/strong&gt; tomando de referencia discos profesionales de categoria &lt;strong&gt;Enterprise&lt;/strong&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Como vemos &lt;strong&gt;la diferencia entre un RAID 0 y un RAID 1 es inmensa&lt;/strong&gt; y la probabilidad de fallo de un &lt;strong&gt;RAID 0&lt;/strong&gt; en el tercer año es de un &lt;strong&gt;8%&lt;/strong&gt;, cifra &lt;strong&gt;inaceptable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Pero si estamos analizando el entorno profesional ¿Por qué estamos hablando de &lt;strong&gt;RAID 0&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Simple: los fabricantes de unidades &lt;strong&gt;SSD&lt;/strong&gt; cada vez que aumentan la &lt;strong&gt;capacidad&lt;/strong&gt; y el &lt;strong&gt;rendimiento&lt;/strong&gt; lo hacen utilizando el concepto de &lt;strong&gt;RAID 0&lt;/strong&gt;, pero... ¿en serio? 😳&lt;/p&gt;

&lt;p&gt;Bueno, aunque el concepto es similar hay diferencia.&lt;/p&gt;

&lt;p&gt;Los &lt;strong&gt;SSD&lt;/strong&gt; están construidos &lt;strong&gt;sumando unidades individuales&lt;/strong&gt; de memoria &lt;strong&gt;flash&lt;/strong&gt; y, &lt;strong&gt;dentro de una misma generación&lt;/strong&gt;, un disco de &lt;strong&gt;2TB&lt;/strong&gt; tiene literalmente el &lt;strong&gt;doble&lt;/strong&gt; de unidades que un disco de &lt;strong&gt;1TB&lt;/strong&gt; a las que la controladora &lt;strong&gt;accede de forma simultánea&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Más allá de esta similitud, un disco &lt;strong&gt;SSD&lt;/strong&gt; se fabrica como una única unidad con una vida útil garantizada por el fabricante por lo que podemos estar tranquilos sin preocuparnos por la arquitectura subyacente.&lt;/p&gt;

&lt;h2&gt;
  
  
  La controladora RAID
&lt;/h2&gt;

&lt;p&gt;Una controladora &lt;strong&gt;hardware RAID&lt;/strong&gt; con discos &lt;strong&gt;HDD&lt;/strong&gt; aporta varias ventajas.&lt;/p&gt;

&lt;p&gt;Por un lado, &lt;strong&gt;descarga al procesador&lt;/strong&gt; porque se encarga de la &lt;strong&gt;gestión de la matriz RAID&lt;/strong&gt; sin que tenga que intervenir el sistema operativo y, por otro lado, &lt;strong&gt;añade protección contra pérdida de datos&lt;/strong&gt; porque la &lt;strong&gt;caché de escritura está protegida&lt;/strong&gt; por una batería.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unidades SSD, algo no encaja
&lt;/h2&gt;

&lt;p&gt;Los bloques de memoria &lt;strong&gt;flash&lt;/strong&gt; de las unidades &lt;strong&gt;SSD&lt;/strong&gt; admiten un &lt;strong&gt;número máximo de ciclos de escritura&lt;/strong&gt; a partir del cual &lt;strong&gt;el bloque puede quedar dañado&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Teniendo en cuenta esta limitación, la &lt;strong&gt;controladora de la unidad SSD&lt;/strong&gt; está programada para distribuir estos ciclos de escritura &lt;a href="https://en.wikipedia.org/wiki/Wear_leveling"&gt;&lt;strong&gt;de forma uniforme entre todos los bloques&lt;/strong&gt;&lt;/a&gt; para alargar su vida útil.&lt;/p&gt;

&lt;p&gt;Permite incluso &lt;strong&gt;redistribuir los datos más mutables&lt;/strong&gt; moviéndolos frecuentemente a &lt;strong&gt;otros bloques&lt;/strong&gt; por lo que es imposible garantizar la ubicación de un dato dentro de la unidad &lt;strong&gt;SSD&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2_4PppiA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Write_Amplification_on_SSD.svg/492px-Write_Amplification_on_SSD.svg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2_4PppiA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Write_Amplification_on_SSD.svg/492px-Write_Amplification_on_SSD.svg.png" alt="Detalle del proceso de redistribución de escrituras en unidades SSD" width="492" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si la &lt;strong&gt;controladora RAID&lt;/strong&gt; espera que la &lt;strong&gt;distribución de los datos sea de forma uniforme&lt;/strong&gt;, en base al esquema de la matriz RAID, y la &lt;strong&gt;controladora de la unidad SSD&lt;/strong&gt; lo hace &lt;strong&gt;de forma aleatoria&lt;/strong&gt; y ambas lo hacen para alargar su vida útil ¿a quién hacemos caso? sin duda a la controladora SSD.&lt;/p&gt;

&lt;p&gt;Cuando se realizan &lt;strong&gt;operaciones de borrado&lt;/strong&gt; el &lt;strong&gt;OS&lt;/strong&gt; informa, enviando comandos &lt;strong&gt;TRIM&lt;/strong&gt;, &lt;strong&gt;a la controladora SSD&lt;/strong&gt; de los &lt;strong&gt;bloques&lt;/strong&gt; que pueden ser borrados y estos &lt;strong&gt;se marcan como libres dejándolos de indexar temporalmente&lt;/strong&gt;. El problema es que &lt;strong&gt;la controladora RAID impide que estos comandos lleguen&lt;/strong&gt; a la unidad SSD. De igual forma el SO tampoco puede acceder a los parámetros SMART.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Es crítico evitar estos problemas&lt;/strong&gt; y se remedia configurando la controladora RAID para funcionar en &lt;strong&gt;modo directo o JBOD&lt;/strong&gt; anulando de facto su funcionalidad.&lt;/p&gt;

&lt;p&gt;Entonces ¿qué ocurre con la protección de la &lt;strong&gt;caché de escritura&lt;/strong&gt; ofrecida por la controladora? Los fabricantes de unidades SSD tienen en cuenta este detalle y &lt;strong&gt;añaden una batería interna&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  La gestión de unidades SSD, un mundo nuevo
&lt;/h2&gt;

&lt;p&gt;¿Quiere decir esto que no existen controladoras RAID para SSD? la respuesta es &lt;strong&gt;que si y a la vez que no&lt;/strong&gt;, porque curiosamente, &lt;a href="https://highpoint-tech.com/USA_new/series-ssd7103-overview.htm"&gt;&lt;strong&gt;las nuevas controladoras RAID SSD&lt;/strong&gt;&lt;/a&gt;, sólo ofrecen los modos &lt;strong&gt;RAID 0&lt;/strong&gt; y &lt;strong&gt;RAID 1&lt;/strong&gt; para permitir que las unidades estén conectadas de forma directa al &lt;strong&gt;OS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;En todo caso las nuevas unidades &lt;strong&gt;NVMe&lt;/strong&gt; ofrecen tasas de &lt;strong&gt;lectura por encima de los 3000 MB/s&lt;/strong&gt; dejando obsoletas a las controladoras simplemente porque no hay ancho de banda para conectar varias unidades en un único bus PCIe.&lt;/p&gt;

&lt;p&gt;¿Existe una &lt;strong&gt;mejor arquitectura&lt;/strong&gt; para gestionar estas unidades?.&lt;/p&gt;

&lt;p&gt;La respuesta vendría de la mano de los &lt;a href="https://www.servethehome.com/supermicro-2029uz-tn20r25m-review-2u-direct-attach-nvme-storage/"&gt;nuevos servidores de almacenamiento &lt;strong&gt;Direct-Attach&lt;/strong&gt;&lt;/a&gt;. Estos servidores conectan el bus &lt;strong&gt;PCIe de cada unidad NVMe directamente al bus PCIe de las distintas CPUs&lt;/strong&gt;. De esa forma se aprovecha todo el potencial del servidor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9Jh74Jib--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.servethehome.com/wp-content/uploads/2020/03/Supermicro-SYS-2029UZ-TN20R25M-System-Diagram.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9Jh74Jib--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.servethehome.com/wp-content/uploads/2020/03/Supermicro-SYS-2029UZ-TN20R25M-System-Diagram.jpg" alt="Supermicro Direct-Attach System Diagram" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;&lt;em&gt;Esquema de un servidor Direct-Attach, &lt;a href="https://www.servethehome.com/wp-content/uploads/2020/03/Supermicro-SYS-2029UZ-TN20R25M-System-Diagram.jpg"&gt;fuente ServeTheHome.&lt;/a&gt;&lt;/em&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Fin de este análisis, no soy un experto así que cualquier dato que consideres se puede ser mejorado te invito a que comentes y compartas 😁&lt;/p&gt;

</description>
      <category>storage</category>
      <category>server</category>
      <category>security</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Canonical MAAS, Metal-As-A-Service, y provisiona tus nodos bare metal de forma elegante</title>
      <dc:creator>Julián Mulet</dc:creator>
      <pubDate>Fri, 01 Oct 2021 07:26:48 +0000</pubDate>
      <link>https://dev.to/uxtechie/canonical-maas-metal-as-a-service-y-provisiona-tus-nodos-bare-metal-de-forma-elegante-2akl</link>
      <guid>https://dev.to/uxtechie/canonical-maas-metal-as-a-service-y-provisiona-tus-nodos-bare-metal-de-forma-elegante-2akl</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;AVISO&lt;/strong&gt;: las imágenes de este post pertenecen a &lt;strong&gt;Canonical&lt;/strong&gt; la cual tiene &lt;strong&gt;todos los derechos reservados&lt;/strong&gt; de las mismas.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introducción
&lt;/h2&gt;

&lt;p&gt;Por razones de &lt;strong&gt;rendimiento&lt;/strong&gt; y/o &lt;strong&gt;costes&lt;/strong&gt; no todas las aplicaciones &lt;strong&gt;Cloud Native&lt;/strong&gt; están alojadas en los grandes proveedores de nube global al estilo de &lt;strong&gt;Amazon AWS&lt;/strong&gt;, &lt;strong&gt;Google Cloud&lt;/strong&gt; o &lt;strong&gt;Microsoft Azure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;También ocurre con muchos otros servicios que no están pensados para la nube y continúan ejecutándose en servidores &lt;strong&gt;bare metal&lt;/strong&gt; dentro de los distintos &lt;a href="https://nixval.com/"&gt;&lt;strong&gt;centros de datos&lt;/strong&gt;&lt;/a&gt; que no pertenecen a estos operadores globales.&lt;/p&gt;

&lt;p&gt;Para estos casos &lt;strong&gt;Canonical&lt;/strong&gt;, la empresa detrás de &lt;strong&gt;Ubuntu Linux&lt;/strong&gt;, tiene disponible una potente herramienta &lt;strong&gt;libre&lt;/strong&gt; de lo más interesante a la vez que desconocida para muchos administradores de sistemas.&lt;/p&gt;

&lt;p&gt;Me refiero a &lt;a href="https://maas.io/"&gt;&lt;strong&gt;MAAS&lt;/strong&gt;&lt;/a&gt; con la que podrás gestionar todos tus servidores de forma desatendida pudiendo elegir entre &lt;strong&gt;VMWare ESXi&lt;/strong&gt;, &lt;strong&gt;Windows&lt;/strong&gt;, &lt;strong&gt;CentOS&lt;/strong&gt;, &lt;strong&gt;RHEL&lt;/strong&gt; y, como no, &lt;strong&gt;Ubuntu&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MAAS&lt;/strong&gt; tiene dos entidades para poder gestionar la infraestructura &lt;strong&gt;TIC&lt;/strong&gt; de una empresa siendo la entidad principal el &lt;strong&gt;controlador de región&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Este controlador ofrece la &lt;strong&gt;interfaz Web&lt;/strong&gt; y una &lt;strong&gt;API REST&lt;/strong&gt; y los servicios globales para gestionar nuestra infraestructura privada (&lt;strong&gt;DNS, NTP, Syslog, Squid Proxy&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;Mi consejo es que esté alojado en tu proveedor de nube de confianza por ser una infraestructura de &lt;strong&gt;Alta Disponibilidad (HA)&lt;/strong&gt; u opcionalmente puedes alojarla en tu infraestructura &lt;a href="https://maas.io/docs/snap/3.0/ui/high-availability#heading--region-controller-ha"&gt;siguiendo estas indicaciones&lt;/a&gt;. En ambos casos la base de datos &lt;strong&gt;Postgres&lt;/strong&gt; tiene que ser &lt;strong&gt;externa&lt;/strong&gt; y en configuración &lt;strong&gt;HA&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Por otro lado, en cada &lt;strong&gt;rack&lt;/strong&gt;, debemos instalar el &lt;strong&gt;controlador de rack&lt;/strong&gt;, la otra entidad de &lt;strong&gt;MAAS&lt;/strong&gt;, que provee de los servicios locales necesarios para gestionar nuestros nodos (&lt;strong&gt;PXE, IPMI, DHCP, TFTP, ISCSI, NTP&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;NOTA:&lt;/strong&gt; El &lt;strong&gt;controlador de rack&lt;/strong&gt; estará alojado en la propia infraestructura del rack y podemos optar por una instalación con soporte &lt;a href="https://maas.io/docs/snap/3.0/ui/high-availability#heading--rack-controller-ha"&gt;&lt;strong&gt;HA&lt;/strong&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HlaWbo0Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://assets.ubuntu.com/v1/b03d95a1-maas.io-how-it-works.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HlaWbo0Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://assets.ubuntu.com/v1/b03d95a1-maas.io-how-it-works.svg" alt="maasHowItWorks" width="308" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;sup&gt;* Sólo visible correctamente con el tema oscuro&lt;/sup&gt;&lt;/center&gt;




&lt;p&gt;&lt;strong&gt;MAAS&lt;/strong&gt; nos permite definir distintas &lt;strong&gt;zonas de disponibilidad&lt;/strong&gt; que reflejarán zonas separadas físicamente bien sea por &lt;strong&gt;rack&lt;/strong&gt;, &lt;strong&gt;sala&lt;/strong&gt; o &lt;strong&gt;centro de datos&lt;/strong&gt;. Estas zonas nos permiten declarar &lt;strong&gt;zonas de fallo aisladas&lt;/strong&gt;, al estilo de los grandes proveedores de nube, para darnos una idea de cómo distribuir mejor las aplicaciones de &lt;strong&gt;HA&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wcgv6LIj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/canonical/image/fetch/f_auto%2Cq_auto%2Cfl_sanitize%2Cw_573%2Ch_258/https://assets.ubuntu.com/v1/d1dc00ae-maas.io-physical-availability-zones.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wcgv6LIj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/canonical/image/fetch/f_auto%2Cq_auto%2Cfl_sanitize%2Cw_573%2Ch_258/https://assets.ubuntu.com/v1/d1dc00ae-maas.io-physical-availability-zones.svg" alt="physical availability zones" width="573" height="258"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Servidores
&lt;/h2&gt;

&lt;p&gt;Cada servidor físico controlado por &lt;strong&gt;MAAS&lt;/strong&gt; estará configurado para que pueda ser apagado, reseteado o encendido a través de su &lt;strong&gt;BMC&lt;/strong&gt; (&lt;strong&gt;IPMI&lt;/strong&gt;, &lt;strong&gt;iLO&lt;/strong&gt;, etc.) y para arrancar desde la red por &lt;strong&gt;PXE-boot&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;NOTA:&lt;/strong&gt; en &lt;strong&gt;MAAS&lt;/strong&gt; a los servidores se les llama &lt;strong&gt;máquina/machine&lt;/strong&gt; y a al resto de dispositivos, routers, switch, etc., &lt;strong&gt;dispositivos/devices&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Para &lt;strong&gt;MAAS&lt;/strong&gt; cada nodo está en un punto de su &lt;strong&gt;ciclo de vida&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2ACzcZlA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/canonical/image/fetch/f_auto%2Cq_auto%2Cfl_sanitize%2Cw_353%2Ch_662/https://assets.ubuntu.com/v1/b2cec06d-maas.io-node-lifecycle.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2ACzcZlA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/canonical/image/fetch/f_auto%2Cq_auto%2Cfl_sanitize%2Cw_353%2Ch_662/https://assets.ubuntu.com/v1/b2cec06d-maas.io-node-lifecycle.svg" alt="node life cycle" width="353" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nuevo/New&lt;/strong&gt;: Podemos dar de alta manualmente una nueva máquina o puede ser detectada cuando arranque por &lt;strong&gt;PXE-boot&lt;/strong&gt; si se detectan automaticamente los parametros para acceder a su &lt;strong&gt;BMC&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Puesta en servicio/Commissioning&lt;/strong&gt;: &lt;strong&gt;MAAS&lt;/strong&gt; arranca la máquina desde una imagen de &lt;strong&gt;Ubuntu&lt;/strong&gt; para recopilar el listado del hardware y añadirlo a su inventario.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lista/Ready&lt;/strong&gt;: el administrador puede pasar a configurar los interfaces de red, particiones de disco, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Asignada/Allocated&lt;/strong&gt;: el administrador ya ha definido su configuración de disco y de red asignando sus &lt;strong&gt;IPs&lt;/strong&gt; que pasan a ser &lt;strong&gt;reservadas&lt;/strong&gt; para esta máquina.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Desplegada/Deploying&lt;/strong&gt;: &lt;strong&gt;MAAS&lt;/strong&gt; instala el &lt;strong&gt;OS&lt;/strong&gt; y configura automáticamente los interfaces de red y las particiones de disco.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Liberada/Releasing&lt;/strong&gt;: el administrador puede dar de baja una máquina liberándola, &lt;strong&gt;MAAS&lt;/strong&gt; iniciará un proceso para borrar el disco de la máquina y dejará de estar disponible para albergar servicios.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sin entrar en profundidad vamos a ver algunos ejemplos del inventario de un servidor en &lt;strong&gt;MAAS&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;Resumen:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cl8IN81c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/1X/7b47235ff57a570ccba6a6ed09186a3d7483f5a4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cl8IN81c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/1X/7b47235ff57a570ccba6a6ed09186a3d7483f5a4.png" alt="machine summary" width="800" height="525"&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;Configuración de red:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vj_UMepA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/2X/c/c5316db130ae05a9cdabcd49ffaa69f0bb405d1d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vj_UMepA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/2X/c/c5316db130ae05a9cdabcd49ffaa69f0bb405d1d.png" alt="machine network" width="800" height="313"&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;Configuración de almacenamiento:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zxAuZQYD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/2X/6/658f4814716a1347fda62ab799ba0d72506c128e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zxAuZQYD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/2X/6/658f4814716a1347fda62ab799ba0d72506c128e.png" alt="machine storage" width="800" height="487"&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Networking
&lt;/h2&gt;

&lt;p&gt;Es una de las partes más potentes ya que nos permite dar de alta todos los recursos relacionados con nuestra &lt;strong&gt;red IP&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fábrica
&lt;/h3&gt;

&lt;p&gt;Es la principal &lt;strong&gt;forma de agrupar a los recursos de red&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Una &lt;strong&gt;fábrica&lt;/strong&gt; la forman &lt;strong&gt;todos los recursos que tienen como finalidad atender a un servicio concreto&lt;/strong&gt; sin relación con otros. Por ejemplo, podemos tener 3 servidores sobre los que trabaja nuestro cluster de &lt;strong&gt;Kubernetes&lt;/strong&gt; con rangos de red y &lt;strong&gt;VLANs&lt;/strong&gt; distintas a otros 2 servidores que dan soporte a un cluster &lt;strong&gt;Proxmox VE&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;En esta línea, podemos ver en la imagen inferior que hay dos &lt;strong&gt;fábricas&lt;/strong&gt; con distintas &lt;strong&gt;subredes&lt;/strong&gt; y &lt;strong&gt;VLANs&lt;/strong&gt; dentro de ellas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JHLk5ERC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://assets.ubuntu.com/v1/657bb332-installconfig-networking__2.4_subnets.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JHLk5ERC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://assets.ubuntu.com/v1/657bb332-installconfig-networking__2.4_subnets.png" alt="subnets" width="800" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;Detalle de una subred:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8LqVVzh8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://assets.ubuntu.com/v1/17617b35-installconfig-networking__2.4_subnets-summary.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8LqVVzh8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://assets.ubuntu.com/v1/17617b35-installconfig-networking__2.4_subnets-summary.png" alt="subnet summary" width="800" height="284"&gt;&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;NOTA:&lt;/strong&gt; &lt;strong&gt;la primera VLAN&lt;/strong&gt; de una fábrica &lt;strong&gt;no está marcada/untagged&lt;/strong&gt; ya que es la utilizada para arrancar los nodos por &lt;strong&gt;PXE-boot&lt;/strong&gt; y es &lt;strong&gt;obligatorio que tenga el servicio DHCP&lt;/strong&gt; activado para asignar al menos una &lt;strong&gt;IP&lt;/strong&gt; al servidor.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Otra forma de entender el concepto de &lt;strong&gt;fábrica&lt;/strong&gt; es que se recomienda configurar nuestros &lt;strong&gt;switches&lt;/strong&gt; y &lt;strong&gt;trunks&lt;/strong&gt; para permitir conectividad directa a nivel de &lt;strong&gt;capa 2&lt;/strong&gt; dentro de la misma mientras que la comunicación entre distintas &lt;strong&gt;fábricas&lt;/strong&gt; necesariamente pase por un &lt;strong&gt;router capa 3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--527QD43e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/1X/46177305128bf7f3190f8a7bbd037c33e96f6a9e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--527QD43e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/1X/46177305128bf7f3190f8a7bbd037c33e96f6a9e.png" alt="MAAS Region scheme" width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Espacio
&lt;/h3&gt;

&lt;p&gt;Es la otra &lt;strong&gt;forma de agrupar a los recursos de red&lt;/strong&gt;, por ejemplo, podemos tener un espacio &lt;strong&gt;WAN&lt;/strong&gt; y otro &lt;strong&gt;LAN&lt;/strong&gt; o &lt;strong&gt;DRBD&lt;/strong&gt; o cualquier concepto que represente una distinción importante &lt;strong&gt;común&lt;/strong&gt; dentro de las distintas &lt;strong&gt;Fábricas&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Máquinas Virtuales
&lt;/h2&gt;

&lt;p&gt;Otra característica que nos ofrece &lt;strong&gt;MAAS&lt;/strong&gt; es la posibilidad de dar de alta a nuestros servidores como &lt;strong&gt;servidores de VM&lt;/strong&gt; para crear sobre ellos nuevas &lt;strong&gt;máquinas&lt;/strong&gt; que a efectos prácticos son idénticas a las físicas pudiendo desplegar los servicios en cualquiera de ellas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Canonical&lt;/strong&gt; ha elegido &lt;strong&gt;LXD&lt;/strong&gt; como soporte para crear las &lt;strong&gt;VM&lt;/strong&gt; lo cual es bastante interesante ya que es una implementación nueva de &lt;strong&gt;LXC&lt;/strong&gt; que entra dentro de la &lt;strong&gt;virtualización ligera&lt;/strong&gt; por lo que podemos esperar que se aprovechen al máximo los recursos de nuestro hardware.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Uqamtfws--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/2X/e/e0cc264a17d67f9530ff8c2ef2bb9522fed0749a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Uqamtfws--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/2X/e/e0cc264a17d67f9530ff8c2ef2bb9522fed0749a.png" alt="LXD VM Project" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Imágenes
&lt;/h2&gt;

&lt;p&gt;Para poder trabajar con los distintos sistemas operativos, &lt;strong&gt;MAAS&lt;/strong&gt;, nos ofrece el apartado para gestionar las imágenes de los mismos.&lt;/p&gt;

&lt;p&gt;Por defecto trabaja con &lt;strong&gt;Ubuntu&lt;/strong&gt; y &lt;strong&gt;CentOS&lt;/strong&gt; pero se pueden &lt;strong&gt;cocinar imágenes personalizadas&lt;/strong&gt; o añadir otros sistemas incluido &lt;strong&gt;Windows&lt;/strong&gt; y sus &lt;strong&gt;licencias&lt;/strong&gt; para poder realizar también instalaciones desatendidas.&lt;/p&gt;

&lt;p&gt;Otra detalle importante es que podemos trabajar con otras arquitecturas, como por ejemplo &lt;strong&gt;arm64&lt;/strong&gt;, de forma que también es una herramienta útil para gestionar infraestructuras de &lt;strong&gt;IoT&lt;/strong&gt; o &lt;strong&gt;Edge computing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pVMbEOCL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/1X/d208922f1126ec92f6ef06cfaa5e16dbbfc613d0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pVMbEOCL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/1X/d208922f1126ec92f6ef06cfaa5e16dbbfc613d0.png" alt="Ubuntu images" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZJUgZQtY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/1X/198aa78b2dd3a650f1b3909ae2c9269e159ca1dc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZJUgZQtY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://discourse.maas.io/uploads/default/original/1X/198aa78b2dd3a650f1b3909ae2c9269e159ca1dc.png" alt="CentOS images" width="800" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hasta aquí hemos visto los conceptos más importantes ya que este post sólo pretende ser una &lt;strong&gt;introducción conceptual&lt;/strong&gt; a esta herramienta tan interesante. La &lt;a href="https://maas.io/docs"&gt;&lt;strong&gt;documentación oficial&lt;/strong&gt;&lt;/a&gt; es muy buena y el resto es cuestión de probarla y adquirir &lt;strong&gt;experiencia&lt;/strong&gt; 😉.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>cloud</category>
      <category>server</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Recursos útiles para mejorar tus publicaciones en Markdown</title>
      <dc:creator>Julián Mulet</dc:creator>
      <pubDate>Fri, 24 Sep 2021 11:16:05 +0000</pubDate>
      <link>https://dev.to/uxtechie/recursos-utiles-para-mejorar-tus-publicaciones-en-markdown-2l4n</link>
      <guid>https://dev.to/uxtechie/recursos-utiles-para-mejorar-tus-publicaciones-en-markdown-2l4n</guid>
      <description>&lt;p&gt;Recientemente he empezado a publicar en &lt;strong&gt;Dev.to&lt;/strong&gt; para mejorar mi &lt;strong&gt;curriculum online&lt;/strong&gt; y, cómo es algo nuevo para mi, he recopilado algunos recursos para usarlos de guía.&lt;/p&gt;

&lt;p&gt;Esta es la lista de los que más me han gustado:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/p/editor_guide"&gt;Guía oficial del editor Dev.to&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/yamadashy/emoji-cheatsheet-of-githubslackdiscordqiita-4d2f#objects"&gt;Uso de emojis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/adam-p/markdown-here/wiki/Markdown-Here-Cheatsheet"&gt;Markdown Cheatsheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devsday.ru/blog/details/38617"&gt;Consejos avanzados para tener más impacto&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Siente libre de explorarlos 😉&lt;/p&gt;

</description>
      <category>markdown</category>
      <category>writing</category>
      <category>spanish</category>
      <category>career</category>
    </item>
    <item>
      <title>Configura AutoFirma con el DNIe en Ubuntu Linux</title>
      <dc:creator>Julián Mulet</dc:creator>
      <pubDate>Fri, 24 Sep 2021 07:54:46 +0000</pubDate>
      <link>https://dev.to/uxtechie/configura-autofirma-con-el-dnie-en-ubuntu-linux-34gh</link>
      <guid>https://dev.to/uxtechie/configura-autofirma-con-el-dnie-en-ubuntu-linux-34gh</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;Nota:&lt;/strong&gt; este post es la continuación de &lt;a href="https://dev.to/sinhouse/configura-tu-dnie-en-ubuntu-linux-para-chrome-y-microsoft-edge-3ehp"&gt;&lt;br&gt;
Configura tu DNIe en Ubuntu Linux para Chrome y Microsoft Edge&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AutoFirma&lt;/strong&gt; es el sistema de firma electrónica desarrollado por la administración pública en España.&lt;/p&gt;

&lt;p&gt;Con este software podemos aprovechar el certificado digital de nuestro &lt;strong&gt;DNIe&lt;/strong&gt; para firmar cualquier documento &lt;strong&gt;generando un fichero nuevo&lt;/strong&gt; con el sufijo &lt;code&gt;_signed.csig&lt;/code&gt;.&lt;br&gt;
Este fichero permite verificar que el original está &lt;strong&gt;firmado por nosotros y que no ha sufrido ninguna modificación&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AutoFirma&lt;/strong&gt; está desarrollado en Java por lo que vamos a instalar el soporte &lt;strong&gt;JRE&lt;/strong&gt; por defecto en &lt;strong&gt;Ubuntu&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;default-jre
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A continuación descargamos el fichero comprimido de &lt;strong&gt;AutoFirma&lt;/strong&gt; para sistemas &lt;strong&gt;Linux&lt;/strong&gt; desde la &lt;a href="https://firmaelectronica.gob.es/Home/Descargas.html"&gt;web oficial&lt;/a&gt; y lo instalamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /tmp/AutoFirma
wget &lt;span class="nt"&gt;-P&lt;/span&gt; /tmp/AutoFirma https://estaticos.redsara.es/comunes/autofirma/1/6/5/AutoFirma_Linux.zip
unzip /tmp/AutoFirma_Linux.zip &lt;span class="nt"&gt;-d&lt;/span&gt; /tmp/AutoFirma
&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg &lt;span class="nt"&gt;-i&lt;/span&gt; /tmp/AutoFirma/AutoFirma_1_6_5.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;Nota&lt;/strong&gt;: Al abrir &lt;strong&gt;AutoFirma&lt;/strong&gt; con el &lt;strong&gt;DNIe&lt;/strong&gt; insertado te pedirá que insertes el &lt;strong&gt;PIN&lt;/strong&gt;&lt;/em&gt;:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZHmt6pEB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/izncyuvedosxf79yy1bi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZHmt6pEB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/izncyuvedosxf79yy1bi.png" alt="enterPIN" width="533" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La primera vez que abras el programa marca la opción &lt;code&gt;No volver a mostrar...&lt;/code&gt; de la parte inferior de la ventana y a continuación pulsa en el botón &lt;code&gt;Usar cualquier certificado&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--isiNa9J4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ogmd6j318cmgfqhu0lx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--isiNa9J4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ogmd6j318cmgfqhu0lx.png" alt="FirstTimeAutoFirmaScreen" width="800" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se abrirá la pantalla principal:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oH3wIwD---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bovducc2to302qheh8uy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oH3wIwD---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bovducc2to302qheh8uy.png" alt="AutoFirmaMainScreen" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y te recomiendo que utilices los siguientes ajustes accediendo al menú &lt;strong&gt;Herramientas -&amp;gt; Preferencias&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--POpBrsCX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eqxn6ywpl8jk5tk08nz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--POpBrsCX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eqxn6ywpl8jk5tk08nz1.png" alt="AutoFirmaConfig" width="602" height="698"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para comprobar que funciona podemos firmar un fichero local &lt;strong&gt;arrastrándolo al cuadro de la ventana principal&lt;/strong&gt; o pulsando en el botón &lt;code&gt;Seleccionar ficheros a firmar&lt;/code&gt;:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oH3wIwD---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bovducc2to302qheh8uy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oH3wIwD---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bovducc2to302qheh8uy.png" alt="AutoFirmaMainScreen" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se abrirá una ventana con los certificados disponibles, selecciona el certificado para &lt;strong&gt;firmar&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OwmYq1zD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0jlimavgwbf2zfzimj3j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OwmYq1zD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0jlimavgwbf2zfzimj3j.png" alt="AutoFirmaSignAction" width="552" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El resultado debe ser similar a este:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JCRpr-27--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wrjqw5qoy1pvlkkj64al.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JCRpr-27--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wrjqw5qoy1pvlkkj64al.png" alt="FileSigned" width="800" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si necesitas hacer el proceso contrario, o sea &lt;strong&gt;verificar que una firma es valida&lt;/strong&gt;, usa la opción del menú &lt;code&gt;Ver firma&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NBPc3Jhs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zq2me58wxyvzl4r78yi4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NBPc3Jhs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zq2me58wxyvzl4r78yi4.png" alt="VerifySign" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Selecciona el fichero de firma y comprueba el resultado:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cy2CXDXi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xo8og9grqapqz0ucts1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cy2CXDXi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xo8og9grqapqz0ucts1p.png" alt="SelectSign" width="476" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VNWPkx4F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bcvh5c5qrr4cl53r4w8s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VNWPkx4F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bcvh5c5qrr4cl53r4w8s.png" alt="ValidSing" width="800" height="705"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Por último, para realizar ciertos tramites con la administración pública será necesario convocar al programa desde el navegador Web, en mi caso uso &lt;strong&gt;Chrome&lt;/strong&gt; pero debería funcionar con el resto sin problemas.&lt;/p&gt;

&lt;p&gt;Abre este enlace para &lt;a href="https://valide.redsara.es/valide/firmar/ejecutar.html"&gt;probar la firma electronica&lt;/a&gt; y pulsa en el botón &lt;code&gt;Firmar&lt;/code&gt;. Saldrá un aviso de seguridad &lt;code&gt;xdg-open&lt;/code&gt; para que permitas abrir la aplicación &lt;strong&gt;AutoFirma&lt;/strong&gt; desde el navegador:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hodSxQAE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f0hotbg3l93nle9jze69.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hodSxQAE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f0hotbg3l93nle9jze69.png" alt="WebSignTest" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y repite el proceso de seleccionar un &lt;strong&gt;fichero&lt;/strong&gt;, introducir el &lt;strong&gt;PIN&lt;/strong&gt; y usar tu certificado para &lt;strong&gt;firmar&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iN2qF5JU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3f6fz3o9ltkztx1pdp5l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iN2qF5JU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3f6fz3o9ltkztx1pdp5l.png" alt="SelectFileToSignWeb" width="476" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZHmt6pEB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/izncyuvedosxf79yy1bi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZHmt6pEB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/izncyuvedosxf79yy1bi.png" alt="enterPIN" width="533" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OwmYq1zD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0jlimavgwbf2zfzimj3j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OwmYq1zD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0jlimavgwbf2zfzimj3j.png" alt="AutoFirmaSignAction" width="552" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¡Si todo ha ido bien el resultado debe ser el siguiente! 🎉:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PcPesBQu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tl6sz29f2upjrmg5bwy4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PcPesBQu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tl6sz29f2upjrmg5bwy4.png" alt="SuccessWebSign" width="800" height="623"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>linux</category>
      <category>security</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>Configura tu DNIe en Ubuntu Linux para Chrome y Microsoft Edge</title>
      <dc:creator>Julián Mulet</dc:creator>
      <pubDate>Thu, 23 Sep 2021 07:06:23 +0000</pubDate>
      <link>https://dev.to/uxtechie/configura-tu-dnie-en-ubuntu-linux-para-chrome-y-microsoft-edge-3ehp</link>
      <guid>https://dev.to/uxtechie/configura-tu-dnie-en-ubuntu-linux-para-chrome-y-microsoft-edge-3ehp</guid>
      <description>&lt;p&gt;En España tenemos la opción de usar el certificado digital de nuestro &lt;strong&gt;DNIe&lt;/strong&gt; para acceder a los servicios online de la administración pública.&lt;/p&gt;

&lt;p&gt;Si eres usuario de &lt;strong&gt;Linux&lt;/strong&gt; te habrás encontrado con varias guías basadas en &lt;strong&gt;Firefox&lt;/strong&gt; pero no es el caso si usas &lt;strong&gt;Chrome&lt;/strong&gt;, &lt;strong&gt;Chromium&lt;/strong&gt; o el mismísimo &lt;a href="https://www.microsoftedgeinsider.com/en-us/download?platform=linux-deb"&gt;&lt;strong&gt;Microsoft Edge&lt;/strong&gt;&lt;/a&gt; 😉.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Nota&lt;/strong&gt;: Esta guía está basada en &lt;strong&gt;Ubuntu LTS 20.04&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A estas alturas ya sabrás que para acceder al certificado necesitas un lector de tarjetas &lt;strong&gt;Smart Card&lt;/strong&gt; y doy por sentado que ya dispones de él, &lt;a href="https://www.dnielectronico.es/portaldnie/PRF1_Cons02.action?pag=REF_300"&gt;más info en la web oficial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lo primero que haremos es instalar el soporte para el lector y las herramientas para gestionar la base de datos de certificados del sistema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;pcscd pcsc-tools
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;libnss3-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora introduce el &lt;strong&gt;DNIe&lt;/strong&gt; en el lector y comprueba que es capaz de leerlo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pcsc_scan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--caDTjb2O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uba62ttbr0mjehtzo7vk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--caDTjb2O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uba62ttbr0mjehtzo7vk.png" alt="DNIeOutput" width="736" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El segundo paso es crear la base de datos de certificados para el usuario actual. La crearemos &lt;strong&gt;sin protección por password&lt;/strong&gt; por lo que, por seguridad, &lt;strong&gt;evitaremos que pueda ser leída por otros usuarios&lt;/strong&gt; del sistema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.pki/nssdb
certutil &lt;span class="nt"&gt;-d&lt;/span&gt; ~/.pki/nssdb &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="nt"&gt;--empty-password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cuando te pida password pulsa &lt;code&gt;Enter&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1Yqq-qve--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/13edworj0imnae7268za.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1Yqq-qve--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/13edworj0imnae7268za.png" alt="CreatedCertsDB" width="587" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Asignamos los permisos adecuados:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;700 ~/.pki/nssdb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para ver que funciona usa el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;certutil &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"sql:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/.pki/nssdb"&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lo normal es que esté vacía:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---ldlrXtA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/snzdrzih0zt80fjuq73v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---ldlrXtA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/snzdrzih0zt80fjuq73v.png" alt="EmptyCertsDB" width="726" height="70"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Descarga el software para distribuciones basadas en &lt;strong&gt;Debian/Ubuntu&lt;/strong&gt; &lt;a href="https://www.dnielectronico.es/descargas/distribuciones_linux/libpkcs11-dnie_1.6.6_amd64.deb"&gt;desde la web oficial&lt;/a&gt; o &lt;a href="https://www.dnielectronico.es/PortalDNIe/PRF1_Cons02.action?pag=REF_1112"&gt;pulsa aquí&lt;/a&gt; para el resto de distribuciones.&lt;/p&gt;

&lt;p&gt;Cuando se inicie la descarga acepta la alerta de seguridad del navegador:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YiUSeH6h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oru39njej3s15brcr5eo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YiUSeH6h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oru39njej3s15brcr5eo.png" alt="DebPackageSecurityAlert" width="800" height="50"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E instala el paquete con el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg &lt;span class="nt"&gt;-i&lt;/span&gt; ~/Descargas/libpkcs11-dnie_1.6.6_amd64.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;¡PRECAUCIÓN!!&lt;/strong&gt; El siguiente paso es &lt;strong&gt;necesario para no dañar la base de datos&lt;/strong&gt;. HAY QUE CERRAR TODOS los navegadores y en mí caso particular, cómo utilizo el &lt;strong&gt;Chrome&lt;/strong&gt;, he introducido el primer comando. Tu solo tienes que usar el adecuado para tu navegador.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pkill &lt;span class="nt"&gt;-o&lt;/span&gt; chrome
pkill &lt;span class="nt"&gt;-o&lt;/span&gt; msedge
pkill &lt;span class="nt"&gt;-o&lt;/span&gt; chromium
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y ya podemos añadir el módulo que gestiona nuestro &lt;strong&gt;DNIe&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;modutil &lt;span class="nt"&gt;-add&lt;/span&gt; &lt;span class="s2"&gt;"DNIe"&lt;/span&gt; &lt;span class="nt"&gt;-dbdir&lt;/span&gt; &lt;span class="s2"&gt;"sql:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/.pki/nssdb"&lt;/span&gt; &lt;span class="nt"&gt;-libfile&lt;/span&gt; /usr/lib/libpkcs11-dnie.so
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comprueba que aparece en el listado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;modutil &lt;span class="nt"&gt;-list&lt;/span&gt; &lt;span class="nt"&gt;-dbdir&lt;/span&gt; ~/.pki/nssdb/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--21SO7baM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g81gvvks5xf1n1uwcx3f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--21SO7baM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g81gvvks5xf1n1uwcx3f.png" alt="DBOutput" width="800" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora solo nos queda abrir el navegador pulsando en el siguiente link de &lt;a href="https://www.sede.fnmt.gob.es/certificados/persona-fisica/verificar-estado/solicitar-verificacion"&gt;verificación del certificado&lt;/a&gt;. El servicio te pedirá que introduzcas el &lt;strong&gt;PIN&lt;/strong&gt; del &lt;strong&gt;DNIe&lt;/strong&gt;, a continuación podrás seleccionarlo y esperar que la validación se complete correctamente:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Bpe8z5jw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e7qcml305tonl1j6y2fj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Bpe8z5jw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e7qcml305tonl1j6y2fj.png" alt="ValidCert" width="720" height="937"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y eso es todo, espero que os sea de utilidad 😄.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Nota:&lt;/strong&gt; este post continua con&lt;br&gt;
&lt;a href="https://dev.to/sinhouse/configura-autofirma-con-el-dnie-en-ubuntu-linux-34gh"&gt;Configura AutoFirma con el DNIe en Ubuntu Linux&lt;br&gt;
&lt;/a&gt; en el caso de que necesites usar &lt;strong&gt;AutoFirma&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>linux</category>
      <category>security</category>
      <category>ubuntu</category>
    </item>
  </channel>
</rss>
