<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://rainbyte.net.ar"><title>(λblog.rainbyte)</title><id>https://rainbyte.net.ar/atom.xml</id><updated>2026-03-08T03:06:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar" rel="alternate"/><link href="https://rainbyte.net.ar/atom.xml" rel="self"/><subtitle>A site about things I enjoy and would like to share</subtitle><entry><title>Restore files on RPi homelab server</title><id>https://rainbyte.net.ar/posts/260308-01-restore-files-on-rpi-homelab-server.html</id><updated>2026-03-08T03:06:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/260308-01-restore-files-on-rpi-homelab-server.html" rel="alternate"/><published>2026-03-08T03:06:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2026-03-08 03:06:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;debian&apos;.&quot; href=&quot;/tags/debian.html&quot;&gt;debian&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;kernel&apos;.&quot; href=&quot;/tags/kernel.html&quot;&gt;kernel&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;linux&apos;.&quot; href=&quot;/tags/linux.html&quot;&gt;linux&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;rpi&apos;.&quot; href=&quot;/tags/rpi.html&quot;&gt;rpi&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;I lost connection to my Raspberry Pi homelab server and then I found it wouldn&apos;t
respond to SSH. After connecting a debug screen, I discovered a message about
corrupted &lt;code&gt;libapparmor&lt;/code&gt; library.&lt;/p&gt;
&lt;p&gt;Since the RPi uses aarch64 architecture, I wasn&apos;t able to easily chroot from my
x86 PC, so I had to restore affected files directly from &lt;code&gt;.deb&lt;/code&gt; packages to the
RPi microsd card.&lt;/p&gt;
&lt;p&gt;This guide explains how to recover a corrupted Debian system on Raspberry Pi by
manually extracting and replacing system files. So let&apos;s go!&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;RPi server stopped responding&lt;/li&gt;
&lt;li&gt;Screen showed &lt;code&gt;libapparmor&lt;/code&gt; corruption error&lt;/li&gt;
&lt;li&gt;Cannot chroot because RPi is aarch64, PC is on x86&lt;/li&gt;
&lt;li&gt;Restored broken library from &lt;code&gt;.deb&lt;/code&gt; directly to microsd&lt;/li&gt;
&lt;li&gt;Booted again, but got kernel panic&lt;/li&gt;
&lt;li&gt;Restored kernel modules from &lt;code&gt;.deb&lt;/code&gt; to microsd&lt;/li&gt;
&lt;li&gt;Booted successfully&lt;/li&gt;
&lt;li&gt;Installed &lt;code&gt;debsums&lt;/code&gt; to verify packages integrity&lt;/li&gt;
&lt;li&gt;Reinstalled other broken packages via apt&lt;/li&gt;
&lt;li&gt;System fully restored&lt;/li&gt;
&lt;/ol&gt;
&lt;!-- more --&gt;
&lt;h2&gt;Solve the first error&lt;/h2&gt;
&lt;p&gt;These are the step-by-step instructions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First, identify the microsd card partition and mount it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;mkdir /tmp/rootfs
sudo mount /dev/sdXN /tmp/rootfs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Find the correct device with &lt;code&gt;lsblk&lt;/code&gt; or &lt;code&gt;blkid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;sdXN&lt;/code&gt; with that partition (eg. &lt;code&gt;sdb2&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Identify the corrupted file by checking error messages from the boot screen,
which in my case mentioned about issues with &lt;code&gt;libapparmor&lt;/code&gt; library&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Get the right &lt;code&gt;.deb&lt;/code&gt; package according to Debian system version:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;curl -o libapparmor1_4.1.0-1_arm64.deb \
  http://http.us.debian.org/debian/pool/main/a/apparmor/libapparmor1_4.1.0-1_arm64.deb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: check &lt;code&gt;/etc/os-release&lt;/code&gt; on your system for the correct version&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Extract &lt;code&gt;data.tar.xz&lt;/code&gt; from package contents:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;ar x libapparmor1_4.1.0-1_arm64.deb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: it can be &lt;code&gt;data.tar.gz&lt;/code&gt; for older packages&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Extract data contents&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For modern &lt;code&gt;.xz&lt;/code&gt; compressed archives:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;tar -xJf data.tar.xz
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For older &lt;code&gt;.gz&lt;/code&gt; compressed archives:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;tar -xzf data.tar.gz
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify if the library is corrupted by comparing the extracted file with the
one on the mounted microsd card partition:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cmp -s \
  usr/lib/aarch64-linux-gnu/libapparmor.so.1.24.2 \
  /tmp/rootfs/lib/aarch64-linux-gnu/libapparmor.so.1.24.2 \
  &amp;amp;&amp;amp; echo &quot;MATCH&quot; || echo &quot;MISMATCH&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: it says &lt;code&gt;MATCH&lt;/code&gt; if files are identical, or &lt;code&gt;MISMATCH&lt;/code&gt; if they differ&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Replace the library if there is a mismatch&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cp \
  usr/lib/aarch64-linux-gnu/libapparmor.so.1.24.2 \
  /tmp/rootfs/lib/aarch64-linux-gnu/libapparmor.so.1.24.2
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the &lt;code&gt;cmp&lt;/code&gt; command again to confirm the files now match&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fix permissions if needed&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo chmod 644 /tmp/rootfs/lib/aarch64-linux-gnu/libapparmor.so.1.24.2
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Kernel recovery&lt;/h2&gt;
&lt;p&gt;After fixing the library, I booted the microsd card but got a kernel panic,
which indicated kernel modules were also corrupted.&lt;/p&gt;
&lt;p&gt;So these steps were the next to be applied:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Download and extract kernel package&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;curl -o linux-image-6.12.62+rpt-rpi-v8_6.12.62-1+rpt1_arm64.deb https://archive.raspberrypi.com/debian/pool/main/l/linux/linux-image-6.12.62+rpt-rpi-v8_6.12.62-1+rpt1_arm64.deb
ar x linux-image-6.12.62+rpt-rpi-v8_6.12.62-1+rpt1_arm64.deb
tar -xJf data.tar.xz
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: Use the kernel version matching your system&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compare boot files between the extracted package and mounted microsd fat32
boot partition:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cmp -s \
  boot/vmlinuz-6.12.62+rpt-rpi-v8 \
  /tmp/rootfs/boot/vmlinuz-6.12.62+rpt-rpi-v8 \
  &amp;amp;&amp;amp; echo &quot;MATCH&quot; || echo &quot;MISMATCH&quot;

cmp -s \
  boot/config-6.12.62+rpt-rpi-v8 \
  /tmp/rootfs/boot/config-6.12.62+rpt-rpi-v8 \
  &amp;amp;&amp;amp; echo &quot;MATCH&quot; || echo &quot;MISMATCH&quot;

cmp -s \
  boot/System.map-6.12.62+rpt-rpi-v8 \
  /tmp/rootfs/boot/System.map-6.12.62+rpt-rpi-v8 \
  &amp;amp;&amp;amp; echo &quot;MATCH&quot; || echo &quot;MISMATCH&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generate checksums for modules from the extracted package:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cd usr/lib/modules/6.12.62+rpt-rpi-v8/
find . -type f -exec sha256sum {} \; | sort &amp;gt; /tmp/hashes_orig.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generate checksums for modules on the microsd card:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cd /tmp/rootfs/usr/lib/modules/6.12.62+rpt-rpi-v8/
find . -type f -exec sha256sum {} \; | sort &amp;gt; /tmp/hashes_card.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: being inside is needed to have same output&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compare the two checksums lists:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;diff -u /tmp/hashes_orig.txt /tmp/hashes_card.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If there are differences then replace affected modules by copying the entire
modules directory or at least overriding the broken files:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo cp -r \
  usr/lib/modules/6.12.62+rpt-rpi-v8/* \
  /tmp/rootfs/usr/lib/modules/6.12.62+rpt-rpi-v8/
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Verify and repair packages&lt;/h2&gt;
&lt;p&gt;Once the system booted, in order to verify package integrity I got some tools:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install debsums&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo apt update
sudo apt install debsums
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run a silent check to list only corrupted files:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo debsums -s
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For each corrupted package do a reinstall, example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo apt install --reinstall \
  libacl1 libassuan9 libcamera0.6 libcc1-0 libcrypt-dev \
  libxmuu1 rpi-usb-gadget vim-common
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: replace with the packages shown by &lt;code&gt;debsums&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify integrity again&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo debsums -s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: if no output, then all packages are intact&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The system is now fully restored!&lt;/p&gt;
&lt;p&gt;This process saved me from re-imaging the microsd card and losing all
configuration.&lt;/p&gt;
&lt;p&gt;It seems I must use an UPS next time &amp;gt;.&amp;lt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Happy hacking!&lt;/code&gt; 🐱&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>Install NVIDIA driver on Debian Trixie</title><id>https://rainbyte.net.ar/posts/260305-01-install-nvidia-driver-on-debian-trixie.html</id><updated>2026-03-05T01:56:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/260305-01-install-nvidia-driver-on-debian-trixie.html" rel="alternate"/><published>2026-03-05T01:56:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2026-03-05 01:56:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;cuda&apos;.&quot; href=&quot;/tags/cuda.html&quot;&gt;cuda&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;debian&apos;.&quot; href=&quot;/tags/debian.html&quot;&gt;debian&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;hardware&apos;.&quot; href=&quot;/tags/hardware.html&quot;&gt;hardware&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;kernel&apos;.&quot; href=&quot;/tags/kernel.html&quot;&gt;kernel&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;linux&apos;.&quot; href=&quot;/tags/linux.html&quot;&gt;linux&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;nvidia&apos;.&quot; href=&quot;/tags/nvidia.html&quot;&gt;nvidia&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;I needed to install NVIDIA driver 590 on Debian 13 (Trixie) because vLLM and
Llama.cpp will require CUDA 13.1, but the Debian repo&apos;s driver 550 only provides
CUDA 12.4.&lt;/p&gt;
&lt;p&gt;So this guide covers two installation methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debian repo
&lt;ul&gt;
&lt;li&gt;simpler management&lt;/li&gt;
&lt;li&gt;officially supported&lt;/li&gt;
&lt;li&gt;limited to CUDA 12.4&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NVIDIA repo
&lt;ul&gt;
&lt;li&gt;provides CUDA 13.1 with driver 590&lt;/li&gt;
&lt;li&gt;recommended for LLM engines&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;TLDR&lt;/h2&gt;
&lt;p&gt;Choose the appropriate method:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;Requirement&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Method to be used&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;CUDA 12.4 (driver 550)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Debian repo method&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;CUDA 13.1 (driver 590)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;NVIDIA repo method&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Both methods will require:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Removing old packages&lt;/li&gt;
&lt;li&gt;Installing headers&lt;/li&gt;
&lt;li&gt;Rebooting when ready&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- more --&gt;
&lt;h2&gt;Debian repo method&lt;/h2&gt;
&lt;p&gt;This method is simpler and works well for most cases.&lt;/p&gt;
&lt;p&gt;For Debian 13 (Trixie) the steps are these:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Remove old NVIDIA packages&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo apt purge &quot;*nvidia*&quot;
sudo apt autoremove
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To enable packages edit &lt;code&gt;/etc/apt/sources.list&lt;/code&gt; and ensure each repo
includes these attributes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;contrib non-free non-free-firmware
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update package definitions&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo apt update
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install essential dependencies&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo apt install linux-headers-amd64 firmware-misc-nonfree
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: firmware is explicit because &lt;code&gt;nvidia-driver&lt;/code&gt; package doesn&apos;t
indicate a dependency on it&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install NVIDIA driver&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo apt install nvidia-driver nvidia-kernel-dkms
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reboot&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo reboot
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install CUDA dependencies (optional)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo apt install nvidia-cuda-toolkit nvidia-cuda-dev nvidia-cuda-toolkit-gcc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: CUDA is required by LLM engines like vLLM and Llama.cpp&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;NVIDIA repo method&lt;/h2&gt;
&lt;p&gt;The NVIDIA repository provides a &lt;a href=&quot;https://docs.nvidia.com/datacenter/tesla/driver-installation-guide/debian.html&quot;&gt;compute-only installation&lt;/a&gt; that avoids X11
dependencies, making it ideal for headless servers like mine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: all steps must be fully completed before rebooting, otherwise
the system will be left unbootable without the driver!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Remove old NVIDIA packages&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo apt purge &quot;*nvidia*&quot;
sudo apt autoremove
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add NVIDIA repository&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;wget https://developer.download.nvidia.com/compute/cuda/repos/debian13/sbsa/cuda-keyring_1.1-1_all.deb
dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt update
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install compute-only system dependencies&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo apt install nvidia-driver-cuda nvidia-kernel-open-dkms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: this is a headless installation that avoids X11 dependencies!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reboot system&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo reboot
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify driver is there by running vendor provided cli tool:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;nvidia-smi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: this shows power usage, temperature, etc&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install CUDA dependencies (optional)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo apt install cuda-compiler-13-1 cuda-libraries-13-1
sudo apt install cuda-libraries-dev-13-1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: CUDA is required by LLM engines like vLLM and Llama.cpp&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add CUDA bin directory to &lt;code&gt;PATH&lt;/code&gt; env var with one of these commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;fish shell:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;fish_add_path /usr/local/cuda/bin
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;bash shell:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;export PATH=${PATH}:/usr/local/cuda/bin
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Provide &lt;code&gt;cicc&lt;/code&gt; and &lt;code&gt;nvcc&lt;/code&gt; at &lt;code&gt;/usr/bin&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo update-alternatives \
    --install /usr/bin/nvcc nvcc /usr/local/cuda/bin/nvcc 100
sudo update-alternatives \
    --install /usr/bin/cicc cicc /usr/local/cuda/nvvm/bin/nvcc 100
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check CUDA &lt;code&gt;nvcc&lt;/code&gt; availability&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;nvcc --version
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Export environment variables&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# Using the symlink as base ensures minor updates are still compatible
export CUDA_HOME=&quot;/usr/local/cuda&quot;

# Add NVCC compiler and CICC internal tools to PATH
export PATH=&quot;$CUDA_HOME/bin:$CUDA_HOME/nvvm/bin:$PATH&quot;

# Some headers are nested, like cub/cub.cuh
export CPATH=&quot;$CUDA_HOME/include/cccl:$CUDA_HOME/include:$CPATH&quot;

# Linking paths: stubs provides -lcuda when building without a live GPU
export LIBRARY_PATH=&quot;$CUDA_HOME/lib64:$CUDA_HOME/lib64/stubs:$LIBRARY_PATH&quot;

# Runtime paths: omit stubs here to avoid runtime conflicts
export LD_LIBRARY_PATH=&quot;$CUDA_HOME/lib64:$LD_LIBRARY_PATH&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: this will be required by LLM engines to recognize CUDA libraries&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To make these permanent, add them to shell&apos;s config file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fish: &lt;code&gt;~/.config/fish/config.fish&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;bash: &lt;code&gt;~/.bashrc&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Follow NVIDIA repo instructions if you need CUDA 13.1 and 590 driver, otherwise
just use the drivers provided in Debian official repo.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Happy hacking!&lt;/code&gt; 🐱&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>Migration from fronma library to inhouse frontmatter parsing</title><id>https://rainbyte.net.ar/posts/260210-01-migration-to-inhouse-frontmatter-parsing.html</id><updated>2026-02-10T03:29:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/260210-01-migration-to-inhouse-frontmatter-parsing.html" rel="alternate"/><published>2026-02-10T03:29:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2026-02-10 03:29:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;rust&apos;.&quot; href=&quot;/tags/rust.html&quot;&gt;rust&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;blog&apos;.&quot; href=&quot;/tags/blog.html&quot;&gt;blog&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;refactoring&apos;.&quot; href=&quot;/tags/refactoring.html&quot;&gt;refactoring&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;I&apos;ve been using the &lt;code&gt;fronma&lt;/code&gt; library for my static blog generator for
more than four years since I migrated my blog from Haskell to Rust
implementation.&lt;/p&gt;
&lt;p&gt;After a period of inactivity, now I reactivated my blog and started
looking at the code again. That&apos;s when I noticed how much I could
improve it!&lt;/p&gt;
&lt;p&gt;Over time I realized I didn&apos;t need most of what &lt;code&gt;fronma&lt;/code&gt; provided, even
if it was fine at the beginning I noticed dependencies are huge for my
usecase.&lt;/p&gt;
&lt;p&gt;Just take a look, my frontmatter format is very simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Page fields:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;title&lt;/code&gt; (just this one)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Blog post fields:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;title&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;author&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;published&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tags&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;language&lt;/code&gt; (optional)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;commentsIssue&lt;/code&gt; (optional)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see I&apos;m not using complex nesting, custom validators,
multiple date formats, or any advanced conversions from YAML format.&lt;/p&gt;
&lt;p&gt;Having all those unused parts means depending on all &lt;code&gt;serde&lt;/code&gt; machinery,
including &lt;code&gt;serde_yaml&lt;/code&gt; which was deprecated 3 years ago, and other big
dependencies.&lt;/p&gt;
&lt;p&gt;Another reason to change was learning itself!&lt;/p&gt;
&lt;p&gt;Given that I built this blog generator to understand how things work in
Rust, sticking with &lt;code&gt;fronma&lt;/code&gt; meant relying on a library for something I
could implement myself.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2&gt;The migration&lt;/h2&gt;
&lt;p&gt;The first thing I did was implementing inline frontmatter parsing in a
compatible way before removing &lt;code&gt;fronma&lt;/code&gt;, so that almost all the existing
code was kept untouched.&lt;/p&gt;
&lt;p&gt;Here is what was changed.&lt;/p&gt;
&lt;h3&gt;Old dependencies&lt;/h3&gt;
&lt;p&gt;My target was removing all these dependencies from &lt;code&gt;Cargo.toml&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;fronma = &quot;0.4&quot;
serde = { version = &quot;1.0&quot;, features = [&quot;derive&quot;] }
serde_json = &quot;1.0.149&quot;
serde_yaml = &quot;0.9&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And in the end I was able to do it.&lt;/p&gt;
&lt;h3&gt;New approach&lt;/h3&gt;
&lt;p&gt;Just using the standard library and &lt;code&gt;TryFrom&lt;/code&gt; trait instead of an
external frontmatter parsing library.&lt;/p&gt;
&lt;p&gt;The idea was to apply traditional string processing subroutines and
common data structures.&lt;/p&gt;
&lt;h3&gt;Code size&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Old implementation size:
&lt;ul&gt;
&lt;li&gt;More than 120 Kb in obvious dependencies D:
&lt;ul&gt;
&lt;li&gt;4 Kb just from the &lt;code&gt;fronma&lt;/code&gt; library itself&lt;/li&gt;
&lt;li&gt;82 Kb from &lt;code&gt;serde&lt;/code&gt; serialization framework&lt;/li&gt;
&lt;li&gt;40 Kb from &lt;code&gt;serde_yaml&lt;/code&gt; lib (deprecated)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;And many more, but I stopped counting there...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;New implementation size:
&lt;ul&gt;
&lt;li&gt;187 lines in my &lt;code&gt;src/main.rs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;This one is tiny! :D&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Implementation details&lt;/h2&gt;
&lt;p&gt;I wrote a generic &lt;code&gt;Frontmatter::parse&lt;/code&gt; function that works with any
struct type comaptible with &lt;code&gt;TryFrom&amp;lt;HashMap&amp;lt;String, String&amp;gt;&amp;gt;&lt;/code&gt; trait.&lt;/p&gt;
&lt;p&gt;The parsing flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Initialize empty &lt;code&gt;HashMap&amp;lt;String, String&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Read content and extract frontmatter lines between &lt;code&gt;---&lt;/code&gt; delimiters&lt;/li&gt;
&lt;li&gt;Parse each line as &lt;code&gt;key: value&lt;/code&gt; and append into the hashmap&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;TryFrom&lt;/code&gt; to convert the hashmap to a typed struct&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&apos;s the function skeleton:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;impl&amp;lt;&apos;a, T&amp;gt; Frontmatter&amp;lt;&apos;a, T&amp;gt;
    where T: TryFrom&amp;lt;HashMap&amp;lt;String, String&amp;gt;, Error = String&amp;gt;
{
    fn parse(contents: &amp;amp;&apos;a str) -&amp;gt; Result&amp;lt;Self, String&amp;gt; {
        // Parse frontmatter into HashMap
        // Validate required fields
        // Return typed Frontmatter
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each header type should be compatible &lt;code&gt;TryFrom&lt;/code&gt; trait, like this one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;impl TryFrom&amp;lt;HashMap&amp;lt;String, String&amp;gt;&amp;gt; for PageHeaders {
    type Error = String;

    fn try_from(
        map: HashMap&amp;lt;String, String&amp;gt;
    ) -&amp;gt; Result&amp;lt;Self, Self::Error&amp;gt; {
        match map.get(&quot;title&quot;) {
            Some(title) =&amp;gt; Ok(Self {
                title: title.clone(),
            }),
            None =&amp;gt; Err(&quot;Missing title in frontmatter&quot;.to_string()),
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For blog posts validation is stricter, but simple to understand:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;impl TryFrom&amp;lt;HashMap&amp;lt;String, String&amp;gt;&amp;gt; for PostHeaders {
    type Error = String;

    fn try_from(
        map: HashMap&amp;lt;String, String&amp;gt;
    ) -&amp;gt; Result&amp;lt;Self, Self::Error&amp;gt; {
        let title = match map.get(&quot;title&quot;) {
            Some(title) =&amp;gt; title.clone(),
            None =&amp;gt; return Err(
                &quot;Missing title in frontmatter&quot;.to_string()
            ),
        };
        let author = match map.get(&quot;author&quot;) {
            Some(author) =&amp;gt; author.clone(),
            None =&amp;gt; return Err(
                &quot;Missing author in frontmatter&quot;.to_string()
            ),
        };
        let published = match map.get(&quot;published&quot;) {
            Some(published) =&amp;gt; published.clone(),
            None =&amp;gt; return Err(
                &quot;Missing published in frontmatter&quot;.to_string()
            ),
        };
        let tags = match map.get(&quot;tags&quot;) {
            Some(tags) =&amp;gt; tags.clone(),
            None =&amp;gt; return Err(
                &quot;Missing tags in frontmatter&quot;.to_string()
            ),
        };
        let language = map.get(&quot;language&quot;).cloned();
        let comments_issue =
            map.get(&quot;commentsIssue&quot;).cloned();

        Ok(Self {
            title,
            author,
            published,
            tags,
            language,
            comments_issue,
        })
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Usage in &lt;code&gt;main&lt;/code&gt; stayed the same, except for these two lines which called
my own parsing wrappers in order to keep code readable:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;...
let fronma = PageHeaders::parse(&amp;amp;contents)?;
...
let fronma = PostHeaders::parse(&amp;amp;contents)?;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see I&apos;m passing contents as reference, so the result will
internally borrow the post body from there as an slice, to avoid the
costly operation of cloning the data into a separated String.&lt;/p&gt;
&lt;h2&gt;Immediate benefits&lt;/h2&gt;
&lt;h3&gt;1. Reduced dependencies&lt;/h3&gt;
&lt;p&gt;My project now depends only on what I actually use, avoiding &lt;code&gt;fronma&lt;/code&gt;
and &lt;code&gt;serde_yaml&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;2. Better understanding&lt;/h3&gt;
&lt;p&gt;Now I know exactly how frontmatter parsing works in my codebase, as it
is just a few lines of code.&lt;/p&gt;
&lt;p&gt;In case of debugging, I won&apos;t need to browse for library source code.&lt;/p&gt;
&lt;h3&gt;3. Customization&lt;/h3&gt;
&lt;p&gt;I can easily extend the parser:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support different delimiter formats&lt;/li&gt;
&lt;li&gt;Add per-field validators&lt;/li&gt;
&lt;li&gt;Implement field transformations&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. Test coverage&lt;/h3&gt;
&lt;p&gt;To verify parsing worked correctly for my usecase I created a set of
tests.&lt;/p&gt;
&lt;p&gt;There were some issues at the beginning with whitespace, but I solved
them by using the explicit &lt;code&gt;\n\&lt;/code&gt; syntax for avoiding spaces on multiline
strings.&lt;/p&gt;
&lt;p&gt;Each test ended up very similar to this one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;#[test]
fn post_header_good() {
    let contents = &quot;---\n\
        title: How-to decrease gnome title-bar height\n\
        author: rainbyte\n\
        published: 2015-07-02 03:15:07\n\
        tags: gnome, snippets, css\n\
        ---\n\
        abc\n\
        def&quot;;
    let result = PostHeaders::parse(contents);
    let fronma = result.unwrap();
    assert_eq!(
        PostHeaders {
            title: &quot;How-to decrease gnome title-bar height&quot;
                .to_string(),
            author: &quot;rainbyte&quot;.to_string(),
            published: &quot;2015-07-02 03:15:07&quot;.to_string(),
            tags: &quot;gnome, snippets, css&quot;.to_string(),
            language: None,
            comments_issue: None,
        },
        fronma.headers
    );
    assert_eq!(
        &quot;abc\n\
        def&quot;,
        fronma.body
    )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So as result all my old posts were rendered to exactly the same html as
before, bit by bit!&lt;/p&gt;
&lt;h2&gt;Future ideas&lt;/h2&gt;
&lt;p&gt;Currently most of the fields are saved as strings, but now that I have
more control over the types I&apos;m planning to type check them by using
stricter timedate and collection types.&lt;/p&gt;
&lt;p&gt;Also given that I reactivated my blog and will be focusing on Rust
development, I&apos;m planning to extend it with more Rust-related content.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Migrating from &lt;code&gt;fronma&lt;/code&gt; to inline inhouse parsing was rewarding, given
that I reduced dependencies, expanded my knowledge, and add some test
coverage.&lt;/p&gt;
&lt;p&gt;For my simple use case, custom parsing is the best choice, and removing
huge dependencies is sometimes the right kind of growth for a project.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Happy hacking&lt;/code&gt; 🐱&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>VSCode column rulers</title><id>https://rainbyte.net.ar/posts/220908-01-vscode-column-rulers.html</id><updated>2022-09-08T21:25:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/220908-01-vscode-column-rulers.html" rel="alternate"/><published>2022-09-08T21:25:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2022-09-08 21:25:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;colors&apos;.&quot; href=&quot;/tags/colors.html&quot;&gt;colors&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;customization&apos;.&quot; href=&quot;/tags/customization.html&quot;&gt;customization&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;vscode&apos;.&quot; href=&quot;/tags/vscode.html&quot;&gt;vscode&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;Today we will configure VSCode to add custom &lt;strong&gt;column rulers&lt;/strong&gt; to measure text
width. This feature doesn&apos;t require any 3rd party extension. Rulers are useful
to indicate us when a line of code is getting &lt;strong&gt;too large&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I recommend a width of maximum 74 or 80 columns for programming code. That
setup is convenient to allow showing files side-by-side.&lt;/p&gt;
&lt;p&gt;VSCode provides &lt;code&gt;color&lt;/code&gt; and &lt;code&gt;column&lt;/code&gt; attributes to customize each ruler. The
colors are expressed by name or as hexadecimal values, and the columns are
just numbers.&lt;/p&gt;
&lt;h2&gt;Configuration steps&lt;/h2&gt;
&lt;p&gt;Follow these steps to create as many column rulers as you want:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open VSCode&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Launch command palette (press &lt;code&gt;ctrl+shift+p&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter &lt;strong&gt;one&lt;/strong&gt; of the following commands to edit config:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Open User Settings (JSON)&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;This one affects all VSCode instances (global config)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Open Workspace Settings (JSON)&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;This one affects only the current project (folder config)&lt;/li&gt;
&lt;li&gt;Config will be saved in &lt;strong&gt;.vscode/settings.json&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To set 2 custom column rulers add a section similar to this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
    &quot;editor.rulers&quot;: [
        60,
        {
            &quot;column&quot;: 80,
            &quot;color&quot;: &quot;#f008&quot;
        },
    ],
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This config creates a 1st ruler at column &lt;code&gt;60&lt;/code&gt; with default color,
and a 2nd ruler with explicit &lt;code&gt;column&lt;/code&gt; and &lt;code&gt;color&lt;/code&gt; fields.&lt;/li&gt;
&lt;li&gt;All the values can be changed as wanted, and even more rulers can
be added.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Save the config to apply the changes each time is modified.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;Happy hacking&lt;/code&gt; 🐱&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>VSCode title-bar colors</title><id>https://rainbyte.net.ar/posts/220903-01-vscode-titlebar-colors.html</id><updated>2022-09-03T15:02:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/220903-01-vscode-titlebar-colors.html" rel="alternate"/><published>2022-09-03T15:02:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2022-09-03 15:02:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;colors&apos;.&quot; href=&quot;/tags/colors.html&quot;&gt;colors&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;customization&apos;.&quot; href=&quot;/tags/customization.html&quot;&gt;customization&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;organization&apos;.&quot; href=&quot;/tags/organization.html&quot;&gt;organization&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;vscode&apos;.&quot; href=&quot;/tags/vscode.html&quot;&gt;vscode&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;Today&apos;s objective is to highlight different projects folders in VSCode by
changing the window title-bars with specific colors. It will be similar to
the &lt;a href=&quot;https://open-vsx.org/extension/johnpapa/vscode-peacock&quot;&gt;Peacock extension&lt;/a&gt; but without any dependencies.&lt;/p&gt;
&lt;p&gt;VSCode allows some UI customization via &lt;code&gt;.json&lt;/code&gt; settings, there are 2 commands to access config files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Open User Settings (JSON)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Open Workspace Settings (JSON)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this case the &lt;strong&gt;Workspace&lt;/strong&gt; command is preferred, given that it affects only
the current folder opened in VSCode.&lt;/p&gt;
&lt;h2&gt;Configuration steps&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open project folder with VSCode&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Launch command palette (press &lt;code&gt;ctrl+shift+p&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter &lt;strong&gt;Open Workspace Settings (JSON)&lt;/strong&gt; command&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To set the custom title-bar color add a code similar to this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
    &quot;workbench.colorCustomizations&quot;: {
        &quot;titleBar.activeBackground&quot;: &quot;#0f0&quot;,
        &quot;titleBar.activeForeground&quot;: &quot;#000&quot;,
        &quot;titleBar.inactiveBackground&quot;: &quot;#0f09&quot;,
        &quot;titleBar.inactiveForeground&quot;: &quot;#0009&quot;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: the numbers can be changed to select other colors&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;Have fun! Happy hacking&lt;/code&gt; 🐱&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>.NET Solutions and Projects for C#</title><id>https://rainbyte.net.ar/posts/220824-02-dotnet-solutions-and-projects-for-csharp.html</id><updated>2022-08-24T23:28:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/220824-02-dotnet-solutions-and-projects-for-csharp.html" rel="alternate"/><published>2022-08-24T23:28:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2022-08-24 23:28:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;c#&apos;.&quot; href=&quot;/tags/c%23.html&quot;&gt;c#&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;dotnet&apos;.&quot; href=&quot;/tags/dotnet.html&quot;&gt;dotnet&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;vscode&apos;.&quot; href=&quot;/tags/vscode.html&quot;&gt;vscode&lt;/a&gt;
    
&lt;/div&gt;

&lt;h3&gt;This publication is a follow up of the &lt;a href=&quot;220824-01-vscode-csharp-setup.html&quot;&gt;VSCode C# setup&lt;/a&gt; post&lt;/h3&gt;
&lt;h2&gt;.NET Solutions&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;dotnet&lt;/code&gt; tool allows us to create projects with the &lt;code&gt;dotnet new&lt;/code&gt; subcommand,
and because of that it is easy to end up with many projects mixed everywhere.&lt;/p&gt;
&lt;p&gt;It is a common practice in C# to group related projects inside a &lt;strong&gt;Solution&lt;/strong&gt;
folder to have them well organized.&lt;/p&gt;
&lt;p&gt;This workflow can also be handled by the &lt;code&gt;dotnet&lt;/code&gt; tool in this way:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a new Solution inside &lt;code&gt;&amp;lt;SolutionName&amp;gt;&lt;/code&gt; folder to contain a group
of related .NET projects&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;dotnet new sln --output &amp;lt;SolutionName&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: &lt;a href=&quot;https://en.wikipedia.org/wiki/Camel_case&quot;&gt;PascalCase&lt;/a&gt; (initial uppercase letters) is preferred for Solution names&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go inside the Solution folder&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cd &amp;lt;SolutionName&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify that there is a &lt;code&gt;.sln&lt;/code&gt; file (eg. using the &lt;code&gt;ls&lt;/code&gt; command)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new project inside &lt;code&gt;&amp;lt;ProjectName&amp;gt;&lt;/code&gt; subfolder:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;dotnet new console --output &amp;lt;ProjectName&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also add the project to the &lt;code&gt;.sln&lt;/code&gt; config:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;dotnet sln add &amp;lt;ProjectName&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: this should be done for each project we want to create&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Modify the project code as needed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Build and execute the project using the following command&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;dotnet run --project &amp;lt;ProjectName&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A project can also be removed from the Solution:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;dotnet sln remove &amp;lt;ProjectName&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The remaining files should be removed by hand:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;rm -rf &amp;lt;ProjectName&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: &lt;strong&gt;be careful&lt;/strong&gt; with &lt;code&gt;rm&lt;/code&gt;, deleted files will disappear forever! 😱&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;VSCode and .NET Solutions&lt;/h2&gt;
&lt;p&gt;This editor also has support for .NET Solutions if the correct extension is installed&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Go inside the Solution folder and start a VSCode instance&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cd &amp;lt;SolutionName&amp;gt;
code .
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If VSCode asks about &lt;strong&gt;adding assets&lt;/strong&gt;, just &lt;strong&gt;ignore&lt;/strong&gt; the message!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Note: the next section will show how to generate the assets for each specific project&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &lt;strong&gt;Extensions&lt;/strong&gt; tab on the left toolbar&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Look for the &lt;a href=&quot;https://open-vsx.org/extension/fernandoescolar/vscode-solution-explorer&quot;&gt;vscode-solution-explorer&lt;/a&gt; extension and install it&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A new &lt;strong&gt;Solution&lt;/strong&gt; tab should appear on the left toolbar&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &lt;strong&gt;Solution&lt;/strong&gt; tab, a list of projects will be shown&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Right-click any project in the list to see the context menu&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select &lt;code&gt;SolutionExplorer: Run&lt;/code&gt; to build and execute that project&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The context menues also allow other options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add a new project&lt;/li&gt;
&lt;li&gt;Create a file (ie. class, interface, etc)&lt;/li&gt;
&lt;li&gt;Remove a project from the Solution&lt;/li&gt;
&lt;li&gt;etc ...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Run &amp;amp; Debug a single Project&lt;/h2&gt;
&lt;p&gt;To use &lt;code&gt;Run &amp;amp; Debug&lt;/code&gt; features the easiest option is to open a single Project
subfolder instead of a Solution folder.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Go inside a Project folder and start a VSCode instance&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cd &amp;lt;SolutionName&amp;gt;/&amp;lt;ProjectName&amp;gt;
code .
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If VSCode asks about &lt;strong&gt;adding assets&lt;/strong&gt;, this time say &lt;strong&gt;yes&lt;/strong&gt; and jump to step 6&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Note: this creates a &lt;code&gt;.vscode&lt;/code&gt; subfolder with the required configurations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Otherwise open a &lt;code&gt;.cs&lt;/code&gt; file to launch C# extension&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to &lt;strong&gt;Run &amp;amp; Debug&lt;/strong&gt; tab on the left toolbar&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click on &lt;code&gt;Generate C# Assets for Build and Debug&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Note: this option only appears if &lt;code&gt;.vscode&lt;/code&gt; assets were not created yet&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Press &lt;code&gt;F5&lt;/code&gt; or the &lt;code&gt;Start Debugging&lt;/code&gt; button in the &lt;strong&gt;Run &amp;amp; Debug&lt;/strong&gt; tab&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Note: this step requires the assets to be already inside the &lt;code&gt;.vscode&lt;/code&gt;
subdirectory&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;Happy hacking!&lt;/code&gt; 🐱&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>VSCode C# setup</title><id>https://rainbyte.net.ar/posts/220824-01-vscode-csharp-setup.html</id><updated>2022-08-23T22:43:30-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/220824-01-vscode-csharp-setup.html" rel="alternate"/><published>2022-08-23T22:43:30-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2022-08-23 22:43:30
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;c#&apos;.&quot; href=&quot;/tags/c%23.html&quot;&gt;c#&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;dotnet&apos;.&quot; href=&quot;/tags/dotnet.html&quot;&gt;dotnet&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;vscode&apos;.&quot; href=&quot;/tags/vscode.html&quot;&gt;vscode&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;Follow these steps to configure a C# development environment using
VSCode (Code-OSS variant) with the Free OmniSharp extension.&lt;/p&gt;
&lt;p&gt;This setup has been tested on &lt;strong&gt;Arch Linux&lt;/strong&gt; with the following package versions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;code&lt;/strong&gt; 1.70.2-1&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dotnet-sdk&lt;/strong&gt; 6.0.8.sdk108-1&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Step-by-step procedure&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install &lt;code&gt;dotnet&lt;/code&gt; sdk and runtime&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Arch Linux setup:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;sudo pacman -S dotnet-sdk
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make a directory anywhere you like. Go inside and use &lt;code&gt;dotnet&lt;/code&gt; tool
to create a sample project with &lt;code&gt;console&lt;/code&gt; template:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;mkdir &amp;lt;ProjectName&amp;gt;
cd &amp;lt;ProjectName&amp;gt;
dotnet new console
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: this folder can be deleted later, it is just an example
to test if the extension is working&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open the editor inside the project folder&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;code .
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install &lt;a href=&quot;https://open-vsx.org/extension/muhammad-sammy/csharp&quot;&gt;free-omnisharp-vscode extension&lt;/a&gt; for C# development&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open &lt;code&gt;Program.cs&lt;/code&gt; file&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Note: this step is just to force extension to download OmniSharp implementation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wait until &lt;strong&gt;OmniSharp&lt;/strong&gt; dependencies get installed (it takes time)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If editor asks about adding &lt;code&gt;build &amp;amp; run&lt;/code&gt; targets, say &lt;code&gt;yes&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It can also be enabled later inside &lt;strong&gt;Run &amp;amp; Debug&lt;/strong&gt; tab&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Press &lt;code&gt;F5&lt;/code&gt; to build and execute the example code&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Breakpoints&lt;/strong&gt; are supported, add them to the left of the code&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;Run &amp;amp; Debug&lt;/strong&gt; tab to see variables and watch expressions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now the editor is configured and new projects can be created using &lt;code&gt;dotnet&lt;/code&gt; tool (like in step 2)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;Happy hacking!&lt;/code&gt; 🐱&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>The HTTP Language</title><id>https://rainbyte.net.ar/posts/220803-01-http-language.html</id><updated>2022-08-03T14:30:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/220803-01-http-language.html" rel="alternate"/><published>2022-08-03T14:30:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2022-08-03 14:30:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;api&apos;.&quot; href=&quot;/tags/api.html&quot;&gt;api&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;http&apos;.&quot; href=&quot;/tags/http.html&quot;&gt;http&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;request&apos;.&quot; href=&quot;/tags/request.html&quot;&gt;request&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;vscode&apos;.&quot; href=&quot;/tags/vscode.html&quot;&gt;vscode&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;It is typical to see the situation where a developer has to work with services which provide an HTTP api.&lt;/p&gt;
&lt;p&gt;Suppose we are implementing the following common endpoints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /todos&lt;/code&gt;: list all the Todos&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /todos&lt;/code&gt;: create a new Todo&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PUT /todos/:id&lt;/code&gt;: update a Todo indicated by :id&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE /todos/:id&lt;/code&gt;: remove a Todo indicated by :id&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After using a particular programming language to achieve the task, it is
possible that we would like to communicate with it to test it works fine.&lt;/p&gt;
&lt;p&gt;There are many tools in the market which allows us to make requests, even
in a graphical point and click way, but I have found more confortable to
have a text representation.&lt;/p&gt;
&lt;p&gt;There is a file format called &lt;code&gt;HTTP language&lt;/code&gt; which can represent requests
in an standardized fashion and it is supported by CLI tools like &lt;code&gt;httpYac&lt;/code&gt;
and editor extensions like &lt;code&gt;vscode-restclient&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;httpYac&lt;/code&gt; tool can be installed using &lt;code&gt;npm&lt;/code&gt; with the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;npm -g install httpyac
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I wrote a few examples about how to make requests to the proposed HTTP api
using the &lt;code&gt;HTTP language&lt;/code&gt; format. It can be seen in the following snippet
that the syntax is very simple and complies with IETF request line spec.&lt;/p&gt;
&lt;h2&gt;HTTP language examples&lt;/h2&gt;
&lt;p&gt;We can obtain a single Todo using the &lt;code&gt;GET&lt;/code&gt; verb followed by the host and
the port where server is running, the HTTP version is optional:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;GET http://localhost:4000/todos HTTP/1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To create a new Todo task we can follow the example and use &lt;code&gt;POST&lt;/code&gt; verb, and
in this case the &lt;code&gt;Content-Type&lt;/code&gt; header should be specified, given that we
are attaching a JSON data structure as body of the request:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;POST http://localhost:4000/todos HTTP/1.1
Content-Type: application/json

{
    &quot;text&quot;: &quot;blabla&quot;,
    &quot;completed&quot;: false
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we want to obtain a single Todo task then a variable could be used to
indicate the &lt;code&gt;:id&lt;/code&gt;, and the value can be accessed using brackets:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;@get-todo-id = a0804e5f-a849-4920-9023-557ecdd790d1
GET http://localhost:4000/todos/{{get-todo-id}} HTTP/1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To modify a Todo task we use the &lt;code&gt;PUT&lt;/code&gt; verb as appears on the proposed API.
It is important to have the &lt;code&gt;Content-Type&lt;/code&gt; header defined as we use JSON:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;@put-todo-id = a0804e5f-a849-4920-9023-557ecdd790d1
PUT http://localhost:4000/todos/{{put-todo-id}} HTTP/1.1
Content-Type: application/json

{
    &quot;text&quot;: &quot;foobar&quot;,
    &quot;completed&quot;: false
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The format can also be used with the &lt;code&gt;DELETE&lt;/code&gt; verb, and in this case we use
a variable one more time, but with different name to avoid conflicts:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;@del-todo-id = a0804e5f-a849-4920-9023-557ecdd790d1
DELETE http://localhost:4000/todos/{{del-todo-id}} HTTP/1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These snippets can be copied to a file with
&lt;code&gt;.rest&lt;/code&gt; or &lt;code&gt;.http&lt;/code&gt; extension, eg. &lt;code&gt;todo-requests.http&lt;/code&gt;, and executed this way:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;httpyac todo-requests.http
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Happy hacking! 🐱&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>Clojure libraries and dependencies</title><id>https://rainbyte.net.ar/posts/220728-01-clojure-libraries-and-dependencies.html</id><updated>2022-07-28T21:49:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/220728-01-clojure-libraries-and-dependencies.html" rel="alternate"/><published>2022-07-28T21:49:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2022-07-28 21:49:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;clojure&apos;.&quot; href=&quot;/tags/clojure.html&quot;&gt;clojure&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;The Clojure language provides some keywords to handle libraries in each file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:require&lt;/code&gt; loads a Clojure library so it can be used in the current file or
in the REPL&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:use&lt;/code&gt; brings definitions to current namespace via aliases&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:import&lt;/code&gt; gives access to native Java classes and interfaces&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: in ClojureScript the native JavaScript code can be usually accessed using
&lt;code&gt;:require&lt;/code&gt;, but sometimes &lt;code&gt;:import&lt;/code&gt; is needed (eg. for Google Closure library).&lt;/p&gt;
&lt;h2&gt;How to use these keywords&lt;/h2&gt;
&lt;p&gt;Load &lt;code&gt;foo.bar&lt;/code&gt; and invoke a function from that library with the
full namespace:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(ns user
  (:require
    [foo.bar]
    [foo.baz]))

(foo.bar/a-function)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Load a library making an alias to simplify access to a function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(ns user
  (:require
    [foo.bar :as bar]
    [foo.baz :as baz]))

(bar/a-function)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Load with &lt;code&gt;:refer&lt;/code&gt; only the definitions we are interested in:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(ns user
  (:require
    [foo.bar :refer [a-function]]))

(a-function)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Load with &lt;code&gt;:refer&lt;/code&gt; only some definitions and also make aliases with &lt;code&gt;:rename&lt;/code&gt;
for our convenience:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(ns user
  (:require
    [foo.bar :refer [a-function]
             :rename [a-function func]]))

(func)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;:use&lt;/code&gt; keyword can be applied with &lt;code&gt;:only&lt;/code&gt; to indicate which definitions
will be provided:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(ns user
  (:use
    [foo.bar :only [a-function]]))

(a-function)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;:use&lt;/code&gt; keyword can also be applied without &lt;code&gt;:only&lt;/code&gt;, but &lt;strong&gt;beware! It can cause
conflicts&lt;/strong&gt;, eg. the following snippet will have a problem if &lt;code&gt;foo.bar&lt;/code&gt; and
&lt;code&gt;foo.baz&lt;/code&gt; namespaces provide definitions with the same name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(ns user
  (:use
    [foo.bar]   ;; avoid :use without :only, it can cause conflicts!
    [foo.baz]))

(a-function)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Import a native Java class of &lt;code&gt;java.util&lt;/code&gt; package and invoke the &lt;code&gt;Date.&lt;/code&gt; method:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(ns user
  (:import
    (java.util Date)))

(Date.) ; call a Java method to get the current date
&lt;/code&gt;&lt;/pre&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>Autenticación en GitHub usando SSH</title><id>https://rainbyte.net.ar/posts/220511-01-github-ssh-auth.html</id><updated>2022-05-11T23:41:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/220511-01-github-ssh-auth.html" rel="alternate"/><published>2022-05-11T23:41:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2022-05-11 23:41:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;git&apos;.&quot; href=&quot;/tags/git.html&quot;&gt;git&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;github&apos;.&quot; href=&quot;/tags/github.html&quot;&gt;github&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;ssh&apos;.&quot; href=&quot;/tags/ssh.html&quot;&gt;ssh&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;Este post se muestra cómo autenticarse en GitHub mediante llaves SSH para poder interactuar con repositorios Git.&lt;/p&gt;
&lt;p&gt;SSH (Secure SHell) es un protocolo que permite acceso remoto trabajando con pares de llaves (o claves) para generar canales seguros de comunicación.&lt;/p&gt;
&lt;p&gt;El procedimiento es similar para otros proveedores de Git, como por ejemplo Bitbucket o GitLab.&lt;/p&gt;
&lt;h2&gt;Registrar una llave pública&lt;/h2&gt;
&lt;p&gt;A continuación se explica como generar un par de llaves, una privada que es secreta, y otra pública que se registrará en GitHub u otro proveedor Git:&lt;/p&gt;
&lt;!-- more --&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Generar el par de llaves SSH reemplazando los campos &lt;code&gt;&amp;lt;email&amp;gt;&lt;/code&gt; y &lt;code&gt;&amp;lt;llave&amp;gt;&lt;/code&gt; con valores apropiados&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;ssh-keygen -t ed25519 -C &amp;lt;email&amp;gt; -f ~/.ssh/&amp;lt;llave&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nota: el nombre &lt;code&gt;id_ed25519_github&lt;/code&gt; podría ser adecuado para el campo
&lt;code&gt;&amp;lt;llave&amp;gt;&lt;/code&gt;, ya que el par de llaves se creó para GitHub usando el esquema
&lt;code&gt;ed25519&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verificar que los archivos &lt;code&gt;~/.ssh/&amp;lt;llave&amp;gt;&lt;/code&gt; y &lt;code&gt;~/.ssh/&amp;lt;llave&amp;gt;.pub&lt;/code&gt; existen, siendo el de extensión &lt;code&gt;.pub&lt;/code&gt; la llave pública (eso significa que puede mostrarse a 3ros sin preocupaciones)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Abrir el archivo &lt;code&gt;~/.ssh/config&lt;/code&gt; con un editor de texto, crearlo si no existe, y dependiendo del sistema operativo agregarle lo siguiente para cada caso:&lt;/p&gt;
&lt;p&gt;Sistema Linux:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Host github.com
  IdentityFile ~/.ssh/&amp;lt;llave&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sistema macOS:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Host github.com
  AddKeysToAgent yes
  UseKeychain    yes
  IdentityFile   ~/.ssh/&amp;lt;llave&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Agregar la llave privada para que el programa &lt;code&gt;ssh-agent&lt;/code&gt; las recuerde&lt;/p&gt;
&lt;p&gt;Sistema Linux:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;ssh-add ~/.ssh/&amp;lt;llave&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sistema macOS:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;ssh-add -K ~/.ssh/&amp;lt;llave&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Agregar la llave pública a GitHub (esto debería ser similar para otros proveedores de repositorios Git)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ir a &lt;code&gt;Settings&lt;/code&gt; en el menú superior derecho&lt;/li&gt;
&lt;li&gt;Abrir &lt;code&gt;SSH and GPG keys&lt;/code&gt; en la columna izquierda&lt;/li&gt;
&lt;li&gt;Clickear el botón &lt;code&gt;New SSH Key&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Llenar el campo &lt;code&gt;Title&lt;/code&gt; a gusto con un nombre representativo&lt;/li&gt;
&lt;li&gt;Ejecutar el comando &lt;code&gt;cat ~/.ssh/&amp;lt;llave&amp;gt;.pub&lt;/code&gt; (¡atención! extensión &lt;code&gt;.pub&lt;/code&gt;), copiar el resultado y pegarlo en el campo &lt;code&gt;Key&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Clickear el botón &lt;code&gt;Save SSH Key&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Repositorios locales&lt;/h2&gt;
&lt;p&gt;Al abrir un repositorio en GitHub se puede obtener la url para clonarlo, para ello debe hacerse click en el botón verde que dice &lt;code&gt;Code ▼&lt;/code&gt;, y luego abrir la pestaña SSH.&lt;/p&gt;
&lt;p&gt;Una dirección url SSH tiene la forma &lt;code&gt;git@github.com:&amp;lt;usuario&amp;gt;/&amp;lt;repositorio&amp;gt;.git&lt;/code&gt;,
y ese repositorio remoto puede clonarse de la siguiente manera:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;git clone &amp;lt;url&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;En caso de tener un repositorio previamente clonado desde un remoto llamado &lt;code&gt;origin&lt;/code&gt; (es lo habitual), es posible cambiar su url así:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;git remote set-url origin &amp;lt;url&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;En ambos casos, y asumiendo que el remoto se llama &lt;code&gt;origin&lt;/code&gt;, se puede verificar
la url del mismo con este comando:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;git remote get-url origin &amp;lt;url&amp;gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>Android folder backup via Rsync</title><id>https://rainbyte.net.ar/posts/220501-01-android-rsync-backup.html</id><updated>2022-05-01T23:41:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/220501-01-android-rsync-backup.html" rel="alternate"/><published>2022-05-01T23:41:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2022-05-01 23:41:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;android&apos;.&quot; href=&quot;/tags/android.html&quot;&gt;android&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;backup&apos;.&quot; href=&quot;/tags/backup.html&quot;&gt;backup&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;rsync&apos;.&quot; href=&quot;/tags/rsync.html&quot;&gt;rsync&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;This post describes how to backup a folder from an Android phone to a PC and restore it on a 2nd phone.&lt;/p&gt;
&lt;h2&gt;Backup procedure&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Download simplesshd on the 1st phone (&lt;a href=&quot;https://play.google.com/store/apps/details?id=org.galexander.sshd&quot;&gt;play store&lt;/a&gt; link)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open simplesshd and click &lt;code&gt;start&lt;/code&gt;. The log will show some relevant information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;host: something like ip &lt;strong&gt;192.168.x.y&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;port: default is &lt;strong&gt;2222&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run rsync backup command on the PC. Replace &lt;code&gt;&amp;lt;host&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;port&amp;gt;&lt;/code&gt; with the correct values for 1st phone!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;rsync -auv --delete -e &apos;ssh -p &amp;lt;port&amp;gt;&apos; &amp;lt;host&amp;gt;:&apos;/sdcard/orig-dir/&apos; &apos;/path/to/backup-dir/&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Rsync will copy files from 1st phone &lt;code&gt;orig-dir&lt;/code&gt; folder to PC &lt;code&gt;backup-dir&lt;/code&gt; folder&lt;/li&gt;
&lt;li&gt;&lt;code&gt;delete&lt;/code&gt; removes from PC folder the files not in the 1st phone&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Note&lt;/u&gt;: final &lt;code&gt;/&lt;/code&gt; on each folder are required!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Restore procedure&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Download simplesshd on the 2nd phone (&lt;a href=&quot;https://play.google.com/store/apps/details?id=org.galexander.sshd&quot;&gt;play store&lt;/a&gt; link)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open simplesshd and click &lt;code&gt;start&lt;/code&gt;. The log will show some relevant information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;host: something like ip &lt;strong&gt;192.168.x.y&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;port: default is &lt;strong&gt;2222&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run rsync restore command on the PC. Replace &lt;code&gt;&amp;lt;host&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;port&amp;gt;&lt;/code&gt; with the correct values for 2nd phone!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;rsync -uv --omit-dir-times --no-perms --recursive --inplace --delete -e &apos;ssh -p &amp;lt;port&amp;gt;&apos; &apos;/path/to/backup-dir/&apos; &amp;lt;host&amp;gt;:&apos;/sdcard/dest-dir/&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Rsync will copy files from PC &lt;code&gt;backup-dir&lt;/code&gt; folder to 2nd phone &lt;code&gt;dest-dir&lt;/code&gt; folder&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inplace&lt;/code&gt; avoids double sdcard write (caused by copy and rename)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;no-perms&lt;/code&gt; is useful when perms are not supported, eg.: mtp mounts&lt;/li&gt;
&lt;li&gt;&lt;code&gt;omit-dir-times&lt;/code&gt; ignores timestamps&lt;/li&gt;
&lt;li&gt;&lt;code&gt;delete&lt;/code&gt; removes from 2nd phone folder the files not in the PC folder&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Note&lt;/u&gt;: final &lt;code&gt;/&lt;/code&gt; on each folder are required!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>Haskell from 0 to IO (Maybe Hero)</title><id>https://rainbyte.net.ar/posts/200828-01-haskell-0-to-io.html</id><updated>2020-08-28T03:56:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/200828-01-haskell-0-to-io.html" rel="alternate"/><published>2020-08-28T03:56:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2020-08-28 03:56:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;haskell&apos;.&quot; href=&quot;/tags/haskell.html&quot;&gt;haskell&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;io&apos;.&quot; href=&quot;/tags/io.html&quot;&gt;io&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;monad&apos;.&quot; href=&quot;/tags/monad.html&quot;&gt;monad&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;typeclasses&apos;.&quot; href=&quot;/tags/typeclasses.html&quot;&gt;typeclasses&lt;/a&gt;
    
&lt;/div&gt;

&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This guide references some syntax and patterns used when writing programs
in the Haskell language. A text editor and the GHC compiler are required
to run the code, but online environments are also an option.&lt;/p&gt;
&lt;h2&gt;Minimal example&lt;/h2&gt;
&lt;p&gt;Haskell expects programs have an entrypoint called &lt;code&gt;main&lt;/code&gt;, which later is
explained in detail, but for now we will create a file named &lt;code&gt;Program.hs&lt;/code&gt;
and write inside the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;-- Comments are written like this
main = print &quot;hola&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check if code can be interpreted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;runghc Program.hs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check if code can be compiled and executed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;ghc -o Program Program.hs
./Program
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some system also require to add the &lt;code&gt;-dynamic&lt;/code&gt; option (eg. Arch Linux).&lt;/p&gt;
&lt;h2&gt;Definitions&lt;/h2&gt;
&lt;p&gt;Haskell definitions indicate a type with &lt;code&gt;::&lt;/code&gt; and their value with &lt;code&gt;=&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here &lt;code&gt;num&lt;/code&gt; is defined with type &lt;code&gt;Int&lt;/code&gt; and value &lt;code&gt;9&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;num :: Int -- type
num = 9    -- definition

main = print num
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;=&lt;/code&gt; symbol means equality in both ways, this means that &lt;code&gt;num&lt;/code&gt; can be
replaced by &lt;code&gt;9&lt;/code&gt; anywhere.&lt;/p&gt;
&lt;p&gt;Detailed definitions are done using &lt;code&gt;let..in..&lt;/code&gt;, which has a &lt;code&gt;let&lt;/code&gt; section
with local values accessed by the &lt;code&gt;in&lt;/code&gt; section to calculate a final value.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;num =
    let x = 5  -- define x
        y = 10 -- define y
    in x + y   -- use them

main = print num
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Other way to have local definitions is to attach a &lt;code&gt;where&lt;/code&gt; section, the
following code is equivalent to the previous one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;num = x + y -- use definitions
  where
    x = 5  -- define x
    y = 10 -- define y

main = print num
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Types&lt;/h2&gt;
&lt;p&gt;Carefully designed types reject unwanted values by making them unrepresentable.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;type&lt;/code&gt; keyword indicates an alias to an existing type.&lt;/p&gt;
&lt;p&gt;Here &lt;code&gt;String&lt;/code&gt; is an alias to a list of &lt;code&gt;Char&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;type String = [Char]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;data&lt;/code&gt; keyword is used to define custom types.&lt;/p&gt;
&lt;p&gt;Booleans are represented in this way:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;data Bool = False | True
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can apply conditionals over booleans like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;b :: Bool
b = True

s :: String
s = if b then &quot;True&quot; else &quot;False&quot;

main = print s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Ordering&lt;/code&gt; type is used to compare things:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;data Ordering = LT | EQ | GT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Handling each possible case for a type is called &lt;code&gt;pattern matching&lt;/code&gt;, and
ideally all of them should be handled&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;ord :: Ordering
ord = LT

s :: String
s = case ord of
    LT -&amp;gt; &quot;Less Than&quot;
    EQ -&amp;gt; &quot;Equal&quot;
    GT -&amp;gt; &quot;Greater Than&quot;

main = print s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Maybe&lt;/code&gt; type is parametrized and represents the existence of something with
a generic type &lt;code&gt;t&lt;/code&gt;, avoiding the use of &lt;code&gt;null&lt;/code&gt; at all.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;data Maybe t = Nothing | Just t
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Pattern matching&lt;/code&gt; also works with parametrized types:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;mInt :: Maybe Int
mInt = Just 9

num :: Int
num = case mInt of
    Just n  -&amp;gt; n
    Nothing -&amp;gt; 0

main = print num
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Either&lt;/code&gt; type has 2 parameters and represents the existence of a value with
type &lt;code&gt;e&lt;/code&gt; or a value with type &lt;code&gt;t&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;data Either e t = Left e | Right t
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can use &lt;code&gt;Either String t&lt;/code&gt; to represent an error message when a result of
type &lt;code&gt;t&lt;/code&gt; cannot be obtained.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;err :: Either String Int
err = Left &quot;Could not obtain the number&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Functions&lt;/h2&gt;
&lt;p&gt;When we see an arrow &lt;code&gt;-&amp;gt;&lt;/code&gt; in a type, we know it is a function.&lt;/p&gt;
&lt;p&gt;Every function receives an &lt;code&gt;a&lt;/code&gt; and gives a &lt;code&gt;b&lt;/code&gt; as result.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;f :: a -&amp;gt; b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Functions indicate their body with &lt;code&gt;=&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;f :: Int -&amp;gt; Int
f x = x + 3

main = print (f 5)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same function can be implemented inline as a lambda&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;f :: Int -&amp;gt; Int
f = \x -&amp;gt; x + 3

main = print (f 5)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can &quot;combine&quot; functions using the &lt;code&gt;.&lt;/code&gt; operator, called &lt;code&gt;composition&lt;/code&gt;, so
that if we have &lt;code&gt;g . f&lt;/code&gt; then &lt;code&gt;f&lt;/code&gt; will produce an intermediate result to be
taken by &lt;code&gt;g&lt;/code&gt; to produce a final result:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;f :: Int -&amp;gt; Int
f x = x + 3

g :: Int -&amp;gt; Int
g x = x * 5

h :: Int -&amp;gt; Int
h = g . f -- be careful with the order

main = print (h 2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is also an &lt;code&gt;$&lt;/code&gt; operator, called &quot;application&quot;, usually used to change
precedence and avoid extra parenthesis. You can think of it as having
parenthesis at both sides.&lt;/p&gt;
&lt;p&gt;Here we have equivalent &lt;code&gt;main&lt;/code&gt; implementations, choose the one you prefer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;f :: Int -&amp;gt; Int
f x = x + 1

-- all of these are equivalent
main1 = print . f $ 3 + 4
main2 = (print . f) $ (3 + 4)
main3 = (print . f) (3 + 4)
main4 = print (f (3 + 4))

main = main1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A function can give a function as result and we can use this mechanism
to make new definitions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;f :: Int -&amp;gt; (Int -&amp;gt; Int)
f x = \y -&amp;gt; x + y

add5 = f 5

main = print (add5 6)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Parenthesis in that type signature can be omitted, and we can also evaluate
the &lt;code&gt;f&lt;/code&gt; function with all the parameters at once:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;f :: Int -&amp;gt; Int -&amp;gt; Int
f x = \y -&amp;gt; x + y

main = print (f 5 6)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can also move the &lt;code&gt;y&lt;/code&gt; parameter to the left side, just to make it easier
to read:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;f :: Int -&amp;gt; Int -&amp;gt; Int
f x y = x + y

main = print (f 5 6)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A function can receive a function as parameter, but then those parenthesis
are required to maintain precedence. We don&apos;t know what the &lt;code&gt;h&lt;/code&gt; function
does, but we know it can be used over an &lt;code&gt;Int&lt;/code&gt; like &lt;code&gt;3&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;g :: (Int -&amp;gt; Int) -&amp;gt; Int
g h = h 3

f x = x + 2

main = print (g f) -- g consumes f function
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Pattern matching&lt;/code&gt; can also be used to define a function piece-by-piece&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;fib :: Int -&amp;gt; Int
fib 0 = 0
fib 1 = 1
fib x = fib (x - 1) + fib (x - 2)

main = print (fib 10)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Typeclasses&lt;/h2&gt;
&lt;p&gt;When types are generic, function body can only use known operations.&lt;/p&gt;
&lt;p&gt;Here type &lt;code&gt;a&lt;/code&gt; could be any type, so &lt;code&gt;x&lt;/code&gt; can only be returned as-is.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;id&apos; :: a -&amp;gt; a
id&apos; x = x

main = print (id&apos; 5)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can define a set of operations, then types could implement them,
that is called &lt;code&gt;typeclass&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As example a type which fulfils the &lt;code&gt;Eq&lt;/code&gt; typeclass will have all its
functions available.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;class Eq a where
    (==) :: a -&amp;gt; a -&amp;gt; Bool
    (/=) :: a -&amp;gt; a -&amp;gt; Bool
    (/=) x y = not (x == y)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that &lt;code&gt;Ord&lt;/code&gt; needs &lt;code&gt;b&lt;/code&gt; to implement &lt;code&gt;Eq&lt;/code&gt;, because it needs
operations from that set.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;class Eq b =&amp;gt; Ord b where
    compare              :: b -&amp;gt; b -&amp;gt; Ordering
    (&amp;lt;), (&amp;lt;=), (&amp;gt;=), (&amp;gt;) :: b -&amp;gt; b -&amp;gt; Bool
    max, min             :: b -&amp;gt; b -&amp;gt; b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Typeclass implementation is done via instances for each type.&lt;/p&gt;
&lt;p&gt;Here we define &lt;code&gt;Eq&lt;/code&gt; for the &lt;code&gt;Bool&lt;/code&gt; type.&lt;/p&gt;
&lt;p&gt;Remember that &lt;code&gt;(/=)&lt;/code&gt; is already defined based on &lt;code&gt;(==)&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;instance Eq Bool where
    (==) True  True  = True
    (==) False False = True
    (==) _     _     = False
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The type &lt;code&gt;t&lt;/code&gt; implements &lt;code&gt;Ord&lt;/code&gt; and &lt;code&gt;Num&lt;/code&gt; typeclasses, so inside &lt;code&gt;isPositive&lt;/code&gt;
we can use number and comparison operations over &lt;code&gt;x&lt;/code&gt; value.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;isPositive :: (Ord t, Num t) =&amp;gt; t -&amp;gt; Bool
isPositive x = compare 0 x
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Input/Output&lt;/h2&gt;
&lt;p&gt;Now we are ready to inspect the type of the &lt;code&gt;main&lt;/code&gt; function we wrote at the
beginning.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;main :: IO ()
main = print &quot;hola&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;IO a&lt;/code&gt; type represents a set of instructions that will be executed
by the runtime of Haskell, with something of type &lt;code&gt;a&lt;/code&gt; as result.&lt;/p&gt;
&lt;p&gt;In the case of main &lt;code&gt;a&lt;/code&gt; is &lt;code&gt;()&lt;/code&gt;, which is called &lt;strong&gt;unit&lt;/strong&gt;, and its only
possible value is &lt;code&gt;()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This means that the &lt;code&gt;main&lt;/code&gt; function produces a set of instructions to be
executed by the runtime when the program is launched.&lt;/p&gt;
&lt;p&gt;We know that &lt;code&gt;print &quot;hola&quot;&lt;/code&gt; type is also &lt;code&gt;IO ()&lt;/code&gt; because it should have
the same type that &lt;code&gt;main&lt;/code&gt; has to be valid code, and we also know that
&lt;code&gt;&quot;hola&quot;&lt;/code&gt; is a &lt;code&gt;String&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We could think that &lt;code&gt;print :: String -&amp;gt; IO ()&lt;/code&gt;, but we have been using
&lt;code&gt;print&lt;/code&gt; with things of other types too, so its type should be something
like &lt;code&gt;C a =&amp;gt; a -&amp;gt; IO ()&lt;/code&gt; with some unknown constraint C.&lt;/p&gt;
&lt;p&gt;That constraint is the &lt;code&gt;Show&lt;/code&gt; typeclass we can see here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;class Show a where
    show :: a -&amp;gt; String
    -- plus other definitions
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Given that &lt;code&gt;show&lt;/code&gt; function takes something and produces a &lt;code&gt;String&lt;/code&gt;, then
that function is the missing piece.&lt;/p&gt;
&lt;p&gt;Then we can infer that &lt;code&gt;print&lt;/code&gt; type is &lt;code&gt;Show a =&amp;gt; a -&amp;gt; IO ()&lt;/code&gt;, so &lt;code&gt;a&lt;/code&gt;
is converted to an &lt;code&gt;String&lt;/code&gt; which is printed.&lt;/p&gt;
&lt;p&gt;This is the definition of the &lt;code&gt;print&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;print :: Show a =&amp;gt; a -&amp;gt; IO ()
print x = putStrLn (show x)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As we can see, it uses &lt;code&gt;show&lt;/code&gt; to obtain an &lt;code&gt;String&lt;/code&gt;, which will be consumed
by the &lt;code&gt;putStrLn&lt;/code&gt; function, and that is the one that has the &lt;code&gt;String -&amp;gt; IO ()&lt;/code&gt;
type we thought before.&lt;/p&gt;
&lt;p&gt;We will see soon how to write bigger programs using &lt;code&gt;IO a&lt;/code&gt; type, but first
we should talk a bit more about typeclasses.&lt;/p&gt;
&lt;h2&gt;Typeclass Laws&lt;/h2&gt;
&lt;p&gt;Some typeclasses define a set of associated laws which cannot be checked
by the compiler, but the code must follow them to preserve the logic.&lt;/p&gt;
&lt;p&gt;Haskell relies on developers to check that their code adheres to the laws,
which could be done via mathematical proofs, but there are also tools to
generate informal tests to check properties (eg. QuickCheck).&lt;/p&gt;
&lt;p&gt;We can take as example the &lt;code&gt;Eq&lt;/code&gt; typeclass we saw before:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;class Eq a where
    (==) :: a -&amp;gt; a -&amp;gt; Bool
    (/=) :: a -&amp;gt; a -&amp;gt; Bool
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A valid &lt;code&gt;Eq&lt;/code&gt; implementation should follow these laws:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reflexivity: &lt;code&gt;x == x = True&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Symmetry: &lt;code&gt;x == y = y == x&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Transitivity: if &lt;code&gt;x == y &amp;amp;&amp;amp; y == z = True&lt;/code&gt;, then &lt;code&gt;x == z = True&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Substitution: if &lt;code&gt;x == y = True&lt;/code&gt;, then &lt;code&gt;f x == f y = True&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Negation: &lt;code&gt;x /= y = not (x == y)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can see that our previous &lt;code&gt;Eq Bool&lt;/code&gt; instance follows &lt;em&gt;reflexivity&lt;/em&gt; law,
because by definition agrees with &lt;code&gt;x == x&lt;/code&gt; form:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;(==) True  True  = True
(==) False False = True
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Given that our implementation is valid, we can always replace &lt;code&gt;x == x&lt;/code&gt;
with &lt;code&gt;True&lt;/code&gt; when we see it, which is useful to simplify our code.&lt;/p&gt;
&lt;p&gt;Typeclass laws help us to refactor the code and make it better using known
properties.&lt;/p&gt;
&lt;h2&gt;Typeclass Examples&lt;/h2&gt;
&lt;p&gt;There are many typeclasses defined in the Haskell libraries, the &lt;a href=&quot;https://wiki.haskell.org/Typeclassopedia&quot;&gt;Typeclassopedia&lt;/a&gt; is a good place to start learning more details
about the standard typeclasses, but I will mention here some of the most common
ones and their laws, just as reference, there is no need to memorize them now
because they will become familiar as time passes.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Semigroup Typeclass&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Types which fulfil &lt;code&gt;Semigroup&lt;/code&gt; api should implement &lt;code&gt;(&amp;lt;&amp;gt;)&lt;/code&gt; function, also
called &lt;code&gt;append&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;class Semigroup a where
    (&amp;lt;&amp;gt;) :: a -&amp;gt; a -&amp;gt; a
    -- other definitions...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following property, called &lt;strong&gt;associativity&lt;/strong&gt;, should be true for
any valid &lt;code&gt;Semigroup&lt;/code&gt; instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(x &amp;lt;&amp;gt; y) &amp;lt;&amp;gt; z = x &amp;lt;&amp;gt; (y &amp;lt;&amp;gt; z)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can use &lt;code&gt;(&amp;lt;&amp;gt;)&lt;/code&gt; function to take to things of the same type and produce
a combined result also of the same type.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;s1 = &quot;hola&quot;
s2 = &quot;mundo&quot;

main = print (s1 &amp;lt;&amp;gt; s2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each &lt;code&gt;Semigroup&lt;/code&gt; instance defines how those things are combined, in this
case &lt;code&gt;String&lt;/code&gt; concatenation occurs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Functor Typeclass&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Types which fulfil &lt;code&gt;Functor&lt;/code&gt; api implement &lt;code&gt;fmap&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;class Functor t where
    fmap :: (a -&amp;gt; b) -&amp;gt; t a -&amp;gt; t b
    -- other definitions...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following properties should be true for any valid &lt;code&gt;Functor&lt;/code&gt; instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fmap id  ==  id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmap (f . g)  ==  fmap f . fmap g&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can use &lt;code&gt;fmap&lt;/code&gt; over a parametrized type &lt;code&gt;t a&lt;/code&gt; to apply a function
&lt;code&gt;a -&amp;gt; b&lt;/code&gt; which takes things of type &lt;code&gt;a&lt;/code&gt; to produce things of type &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here &lt;code&gt;fmap&lt;/code&gt; is applied over a parametrized &lt;code&gt;List Int&lt;/code&gt; to apply &lt;code&gt;f&lt;/code&gt; function
which will add 3 to each integer inside the list, obtaining a new list with
the same shape but new values.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;xs :: [Int]
xs = [1, 2, 3]

f :: Int -&amp;gt; Int
f x = x + 3

main = print (fmap f xs)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember, &lt;code&gt;fmap&lt;/code&gt; behavior depends on the specific parametrized type we are
working with, eg. in the case of data structures usually allows us to apply
a function over each element preserving the structure shape.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Applicative Typeclass&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Types which fulfil &lt;code&gt;Applicative&lt;/code&gt; api should implement the required functions
(ie. &lt;code&gt;pure&lt;/code&gt;, &lt;code&gt;(&amp;lt;*&amp;gt;)&lt;/code&gt;, etc) and must have a &lt;code&gt;Functor&lt;/code&gt; instance as well, so
the &lt;code&gt;fmap&lt;/code&gt; function will be available as well.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;class Functor t =&amp;gt; Applicative t where
    pure :: a -&amp;gt; t a
    (&amp;lt;*&amp;gt;) :: t (a -&amp;gt; b) -&amp;gt; t a -&amp;gt; t b
    -- other definitions...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following properties should be true for any &lt;code&gt;Applicative&lt;/code&gt; instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pure id &amp;lt;*&amp;gt; v = v&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pure (.) &amp;lt;*&amp;gt; u &amp;lt;*&amp;gt; v &amp;lt;*&amp;gt; w = u &amp;lt;*&amp;gt; (v &amp;lt;*&amp;gt; w)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pure f &amp;lt;*&amp;gt; pure x = pure (f x)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;u &amp;lt;*&amp;gt; pure y = pure ($ y) &amp;lt;*&amp;gt; u&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;pure&lt;/code&gt; function is really useful when working with a parametrized type
&lt;code&gt;t a&lt;/code&gt; (eg. &lt;code&gt;IO a&lt;/code&gt;, &lt;code&gt;Maybe a&lt;/code&gt;, etc) because it allows us to take something
of type &lt;code&gt;a&lt;/code&gt; and generate a value of type &lt;code&gt;t a&lt;/code&gt; in a predefined way.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;main = pure ()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example shows a program which does nothing, but it is interesting
anyway because we can see how &lt;code&gt;pure&lt;/code&gt; obtains a &lt;code&gt;IO a&lt;/code&gt; from an &lt;code&gt;a&lt;/code&gt;, which
in this case is the unit type.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Monad Typeclass&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Any type which implements &lt;code&gt;Monad&lt;/code&gt; will have a &lt;code&gt;(&amp;gt;&amp;gt;=)&lt;/code&gt; operation, called
&lt;code&gt;bind&lt;/code&gt;, it should also implement &lt;code&gt;Applicative&lt;/code&gt; and &lt;code&gt;Functor&lt;/code&gt; api as well,
so we also have the &lt;code&gt;pure&lt;/code&gt; and &lt;code&gt;fmap&lt;/code&gt; functions available for &lt;code&gt;Monad&lt;/code&gt;
instances.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;class Applicative m =&amp;gt; Monad m where
    (&amp;gt;&amp;gt;=) :: m a -&amp;gt; (a -&amp;gt; m b) -&amp;gt; m b
    -- other definitions...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we see &lt;code&gt;mf &amp;gt;&amp;gt;= k&lt;/code&gt; we know &lt;code&gt;k&lt;/code&gt; consumes something of type &lt;code&gt;a&lt;/code&gt; obtained
from &lt;code&gt;mf&lt;/code&gt; (because &lt;code&gt;mf :: m a&lt;/code&gt; and &lt;code&gt;k :: (a -&amp;gt; m b)&lt;/code&gt;), so we can say &lt;code&gt;k&lt;/code&gt; is
a &lt;strong&gt;continuation&lt;/strong&gt;, because it could be the next piece to be executed.&lt;/p&gt;
&lt;p&gt;Keep in mind that the following properties are required for any valid
&lt;code&gt;Monad&lt;/code&gt; instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pure a &amp;gt;&amp;gt;= k  =  k a&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mf &amp;gt;&amp;gt;= pure = mf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mf &amp;gt;&amp;gt;= (\x -&amp;gt; k x &amp;gt;&amp;gt;= h)  =  (mf &amp;gt;&amp;gt;= k) &amp;gt;&amp;gt;= h&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt; function is useful when we have something of a parametrized type
&lt;code&gt;t a&lt;/code&gt; and we want to process the values of type &lt;code&gt;a&lt;/code&gt; with the condition that
in the end we should produce something of type &lt;code&gt;t b&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;f :: Int -&amp;gt; String
f n = &quot;n = &quot; &amp;lt;&amp;gt; show n

mInt :: Maybe Int
mInt = Nothing

main = print (mInt &amp;gt;&amp;gt;= (pure . f))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example we have &lt;code&gt;mInt&lt;/code&gt; of type &lt;code&gt;Maybe Int&lt;/code&gt; and we would like to
process that &lt;code&gt;Int&lt;/code&gt; with the function &lt;code&gt;f&lt;/code&gt; to obtain an &lt;code&gt;String&lt;/code&gt;, so we
use the bind function &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt; to do handle this and give &lt;code&gt;pure . f&lt;/code&gt; as
continuation, so it conforms with the expected type &lt;code&gt;Int -&amp;gt; Maybe String&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The parametrized type &lt;code&gt;Maybe a&lt;/code&gt; has a bind implementation which is
intelligent enough to note that the &lt;code&gt;a&lt;/code&gt; (ie. &lt;code&gt;Int&lt;/code&gt;) doesn&apos;t exist,
because &lt;code&gt;mInt&lt;/code&gt; value is &lt;code&gt;Nothing&lt;/code&gt;, so bind avoids calling &lt;code&gt;pure . f&lt;/code&gt;
as the continuation expects the &lt;code&gt;Int&lt;/code&gt; to be there.&lt;/p&gt;
&lt;p&gt;We can se that &lt;code&gt;pure . f&lt;/code&gt; uses &lt;code&gt;pure&lt;/code&gt; to conform with &lt;code&gt;Int -&amp;gt; Maybe Int&lt;/code&gt;
type, and it could have consumed an &lt;code&gt;Int&lt;/code&gt; if &lt;code&gt;mInt&lt;/code&gt; had it
(eg. &lt;code&gt;mInt = Just 4&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;As we can see, bind mechanism and meaning are related to the parametrized
type which implements the &lt;code&gt;Monad&lt;/code&gt; instance, so we need to understand that
type very well before learning about the inner working of a certain
typeclass instance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Do-notation&lt;/h2&gt;
&lt;p&gt;Finally, as promised, we can see how to write bigger programs using &lt;code&gt;IO a&lt;/code&gt;
type.&lt;/p&gt;
&lt;p&gt;First we can see a piece of code which uses &lt;code&gt;(&amp;gt;&amp;gt;=)&lt;/code&gt; operator to obtain a
&lt;code&gt;String&lt;/code&gt; written by the user and then prints it to the console.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;main = getLine &amp;gt;&amp;gt;= putStrLn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can rewrite it using an explicit parameter named &lt;code&gt;line&lt;/code&gt;, which is produced
by &lt;code&gt;getLine&lt;/code&gt; subroutine and passed to the continuation (remember that when we
see something like &lt;code&gt;mf &amp;gt;&amp;gt;= k&lt;/code&gt;, then &lt;code&gt;k&lt;/code&gt; is the continuation).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;main = getLine &amp;gt;&amp;gt;= (\line -&amp;gt; putStrLn line)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As this gets tiring really quickly, Haskell defines a special syntax called
&lt;code&gt;do-notation&lt;/code&gt;, which we can use to write equivalent code in a more familiar
style.&lt;/p&gt;
&lt;p&gt;Like in 2nd example &lt;code&gt;getLine&lt;/code&gt; result is available as &lt;code&gt;line&lt;/code&gt; value.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;main = do
    line &amp;lt;- getLine
    putStrLn line
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As a final example we have an imperative-style program which asks the user
for an input and then iterates over the elements of a list printing the
user input each time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;import Control.Monad (forM_)

xs = [1..10]

main = do
    line &amp;lt;- getLine
    forM_ xs $ \x -&amp;gt; do
        putStrLn (line &amp;lt;&amp;gt; show x)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are other ways to write this program, but this can feel familiar to
programmers which already know other languages.&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
    // This is a self executing function
    var issueId = 6;
    var url = &quot;https://github.com/rainbyte/rainbyte.github.io/issues/&quot; + issueId;
    var api_url = &quot;https://api.github.com/repos/rainbyte/rainbyte.github.io/issues/&quot; + issueId + &quot;/comments&quot;;
    (function() {
        // DOM is already available, now we can handle page elements
        var ghCommentsList = document.getElementById(&quot;gh-comments-list&quot;);

        var request = new XMLHttpRequest();
        request.open(&apos;GET&apos;, api_url, true);
        request.onload = function() {
            if (request.status &gt;= 200 &amp;&amp; request.status &lt; 400) {
                // Request was successful, we can process the raw comments
                var comments = JSON.parse(request.responseText);
                var fragment = document.createDocumentFragment();
                var range = new Range();

                // Render comments section header
                fragment.appendChild(range.createContextualFragment(`
                    &lt;div&gt;
                        &lt;b&gt;Comments section&lt;/b&gt; (visit the &lt;b&gt;&lt;a href=&apos;${url}&apos;&gt;issue&lt;/a&gt;&lt;/b&gt; of this post to add one)
                    &lt;/div&gt;
                `));

                // Render view of each comment
                comments.forEach(comment =&gt; {
                    var date = new Date(comment.created_at);
                    var renderedComment = range.createContextualFragment(`
                        &lt;div class=&apos;gh-comment&apos;&gt;
                            &lt;div class=&apos;gh-comment-header&apos;&gt;
                                &lt;img src=&apos;${comment.user.avatar_url}&apos;&gt;
                                &lt;div&gt;
                                    &lt;b&gt;&lt;a href=&apos;${comment.user.html_url}&apos;&gt;${comment.user.login}&lt;/a&gt;&lt;/b&gt; posted at &lt;em&gt;${date.toDateString()}&lt;/em&gt;
                                &lt;/div&gt;
                            &lt;/div&gt;
                            &lt;div class=&apos;gh-comment-body&apos;&gt;
                                ${comment.body}
                            &lt;/div&gt;
                        &lt;/div&gt;
                    `);
                    fragment.appendChild(renderedComment);
                });

                // Make changes visible by adding rendered nodes
                ghCommentsList.append(fragment);
            } else {
                // Request reached the target server, but it returned an error
                ghCommentsList.append(&quot;Comments are not available now.&quot;);
            }
        };
        request.onerror = function() {
            // There was a connection error of some sort
            ghCommentsList.append(&quot;Comments are not available now.&quot;);
        };
        request.send();
    })();
&lt;/script&gt;
</summary></entry><entry><title>Using Kotlin coroutines to handle blocking computations in Android</title><id>https://rainbyte.net.ar/posts/200518-01-kotlin-coroutines-android.html</id><updated>2020-05-18T05:23:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/200518-01-kotlin-coroutines-android.html" rel="alternate"/><published>2020-05-18T05:23:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2020-05-18 05:23:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;android&apos;.&quot; href=&quot;/tags/android.html&quot;&gt;android&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;async&apos;.&quot; href=&quot;/tags/async.html&quot;&gt;async&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;coroutines&apos;.&quot; href=&quot;/tags/coroutines.html&quot;&gt;coroutines&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;kotlin&apos;.&quot; href=&quot;/tags/kotlin.html&quot;&gt;kotlin&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;When we need to execute time intensive computations and show some the result
to the user, we should avoid running them inside UI thread, otherwise app UI
could get frozen.&lt;/p&gt;
&lt;p&gt;Here we have a detailed example which uses a coroutine to run Fibonacci fib
function without blocking app UI:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;class MainActivity : AppCompatActivity(), CoroutineScope {

    // Blocking computation, requires too much time to finish
    fun fib(x: Int): Int = if (x &amp;lt;= 1) x else fib(x - 1) + fib(x - 2)

    // Attach coroutines context to activity
    override val coroutineContext: CoroutineContext =
            Dispatchers.Main + SupervisorJob()

    // Coroutines should respect activity lifetime
    override fun onDestroy() {
        super.onDestroy()
        coroutineContext[Job]!!.cancel()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btnCalc.setOnClickListener {
            val number: Int = editNumber.text.toString().toInt()
            // Start coroutine on the context attached to activity
            this.launch {
                // Switch to IO dispatcher to perform blocking computation
                val result = withContext(Dispatchers.IO) {
                    fib(number)
                }
                if (result != null) {
                    editResult.setText(result.toString())
                }
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;UI code is also provided to complete the example&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;
&amp;lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:orientation=&quot;vertical&quot;
    android:layout_margin=&quot;10dp&quot;
    tools:context=&quot;.MainActivity&quot;&amp;gt;

    &amp;lt;TextView
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot;Number&quot; /&amp;gt;

    &amp;lt;EditText
        android:id=&quot;@+id/editNumber&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot; /&amp;gt;

    &amp;lt;TextView
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot;Result&quot; /&amp;gt;

    &amp;lt;EditText
        android:id=&quot;@+id/editResult&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot; /&amp;gt;

    &amp;lt;Button
        android:id=&quot;@+id/btnCalc&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot;Calculate fib(number)&quot; /&amp;gt;

&amp;lt;/LinearLayout&amp;gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
    // This is a self executing function
    var issueId = 5;
    var url = &quot;https://github.com/rainbyte/rainbyte.github.io/issues/&quot; + issueId;
    var api_url = &quot;https://api.github.com/repos/rainbyte/rainbyte.github.io/issues/&quot; + issueId + &quot;/comments&quot;;
    (function() {
        // DOM is already available, now we can handle page elements
        var ghCommentsList = document.getElementById(&quot;gh-comments-list&quot;);

        var request = new XMLHttpRequest();
        request.open(&apos;GET&apos;, api_url, true);
        request.onload = function() {
            if (request.status &gt;= 200 &amp;&amp; request.status &lt; 400) {
                // Request was successful, we can process the raw comments
                var comments = JSON.parse(request.responseText);
                var fragment = document.createDocumentFragment();
                var range = new Range();

                // Render comments section header
                fragment.appendChild(range.createContextualFragment(`
                    &lt;div&gt;
                        &lt;b&gt;Comments section&lt;/b&gt; (visit the &lt;b&gt;&lt;a href=&apos;${url}&apos;&gt;issue&lt;/a&gt;&lt;/b&gt; of this post to add one)
                    &lt;/div&gt;
                `));

                // Render view of each comment
                comments.forEach(comment =&gt; {
                    var date = new Date(comment.created_at);
                    var renderedComment = range.createContextualFragment(`
                        &lt;div class=&apos;gh-comment&apos;&gt;
                            &lt;div class=&apos;gh-comment-header&apos;&gt;
                                &lt;img src=&apos;${comment.user.avatar_url}&apos;&gt;
                                &lt;div&gt;
                                    &lt;b&gt;&lt;a href=&apos;${comment.user.html_url}&apos;&gt;${comment.user.login}&lt;/a&gt;&lt;/b&gt; posted at &lt;em&gt;${date.toDateString()}&lt;/em&gt;
                                &lt;/div&gt;
                            &lt;/div&gt;
                            &lt;div class=&apos;gh-comment-body&apos;&gt;
                                ${comment.body}
                            &lt;/div&gt;
                        &lt;/div&gt;
                    `);
                    fragment.appendChild(renderedComment);
                });

                // Make changes visible by adding rendered nodes
                ghCommentsList.append(fragment);
            } else {
                // Request reached the target server, but it returned an error
                ghCommentsList.append(&quot;Comments are not available now.&quot;);
            }
        };
        request.onerror = function() {
            // There was a connection error of some sort
            ghCommentsList.append(&quot;Comments are not available now.&quot;);
        };
        request.send();
    })();
&lt;/script&gt;
</summary></entry><entry><title>Plantillas de Gnome</title><id>https://rainbyte.net.ar/posts/191207-01-plantillas.html</id><updated>2019-12-07T02:51:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/191207-01-plantillas.html" rel="alternate"/><published>2019-12-07T02:51:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2019-12-07 02:51:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;gnome&apos;.&quot; href=&quot;/tags/gnome.html&quot;&gt;gnome&lt;/a&gt;
    
&lt;/div&gt;

&lt;h2&gt;Plantillas de Gnome&lt;/h2&gt;
&lt;p&gt;Gnome posee una carpeta &lt;code&gt;~/Plantillas&lt;/code&gt; en la cual es posible agregar archivos como base para crear nuevos documentos de forma automática.&lt;/p&gt;
&lt;p&gt;Muchas veces se da el caso de crear documentos con cierto contenido que se repite en cada uno de ellos, por ejemplo los archivos .desktop:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-desktop&quot;&gt;[Desktop Entry]

Type=Application
Name=Firefox
Exec=/usr/bin/firefox
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Como puede verse, estos documentos siempre tienen la misma cabecera y algunas opciones que deben estar allí siempre (ej. &lt;code&gt;Type&lt;/code&gt; y &lt;code&gt;Name&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Como solución podríamos crear un archivo &lt;code&gt;~/Plantillas/Nuevo Desktop Entry.desktop&lt;/code&gt;, para evitar tipear esas cosas, algo asi:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-desktop&quot;&gt;[Desktop Entry]

Type=Application
Name=${nombre}
Exec=${comando}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Luego desde Nautilus podemos hacer click derecho e ir al menú &lt;code&gt;Nuevo documento...&lt;/code&gt; y allí ver nuestra plantilla.&lt;/p&gt;
&lt;p&gt;Finalmente es cuestión de cambiar el nombre y rellenar los campos (ej. &lt;code&gt;${nombre}&lt;/code&gt; y &lt;code&gt;${comando}&lt;/code&gt;).&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
    // This is a self executing function
    var issueId = 3;
    var url = &quot;https://github.com/rainbyte/rainbyte.github.io/issues/&quot; + issueId;
    var api_url = &quot;https://api.github.com/repos/rainbyte/rainbyte.github.io/issues/&quot; + issueId + &quot;/comments&quot;;
    (function() {
        // DOM is already available, now we can handle page elements
        var ghCommentsList = document.getElementById(&quot;gh-comments-list&quot;);

        var request = new XMLHttpRequest();
        request.open(&apos;GET&apos;, api_url, true);
        request.onload = function() {
            if (request.status &gt;= 200 &amp;&amp; request.status &lt; 400) {
                // Request was successful, we can process the raw comments
                var comments = JSON.parse(request.responseText);
                var fragment = document.createDocumentFragment();
                var range = new Range();

                // Render comments section header
                fragment.appendChild(range.createContextualFragment(`
                    &lt;div&gt;
                        &lt;b&gt;Comments section&lt;/b&gt; (visit the &lt;b&gt;&lt;a href=&apos;${url}&apos;&gt;issue&lt;/a&gt;&lt;/b&gt; of this post to add one)
                    &lt;/div&gt;
                `));

                // Render view of each comment
                comments.forEach(comment =&gt; {
                    var date = new Date(comment.created_at);
                    var renderedComment = range.createContextualFragment(`
                        &lt;div class=&apos;gh-comment&apos;&gt;
                            &lt;div class=&apos;gh-comment-header&apos;&gt;
                                &lt;img src=&apos;${comment.user.avatar_url}&apos;&gt;
                                &lt;div&gt;
                                    &lt;b&gt;&lt;a href=&apos;${comment.user.html_url}&apos;&gt;${comment.user.login}&lt;/a&gt;&lt;/b&gt; posted at &lt;em&gt;${date.toDateString()}&lt;/em&gt;
                                &lt;/div&gt;
                            &lt;/div&gt;
                            &lt;div class=&apos;gh-comment-body&apos;&gt;
                                ${comment.body}
                            &lt;/div&gt;
                        &lt;/div&gt;
                    `);
                    fragment.appendChild(renderedComment);
                });

                // Make changes visible by adding rendered nodes
                ghCommentsList.append(fragment);
            } else {
                // Request reached the target server, but it returned an error
                ghCommentsList.append(&quot;Comments are not available now.&quot;);
            }
        };
        request.onerror = function() {
            // There was a connection error of some sort
            ghCommentsList.append(&quot;Comments are not available now.&quot;);
        };
        request.send();
    })();
&lt;/script&gt;
</summary></entry><entry><title>Pandoc filter for custom ruby notation</title><id>https://rainbyte.net.ar/posts/181122-01-pandoc-filter-ruby.html</id><updated>2018-11-22T03:12:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/181122-01-pandoc-filter-ruby.html" rel="alternate"/><published>2018-11-22T03:12:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2018-11-22 03:12:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;blog&apos;.&quot; href=&quot;/tags/blog.html&quot;&gt;blog&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;haskell&apos;.&quot; href=&quot;/tags/haskell.html&quot;&gt;haskell&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;pandoc&apos;.&quot; href=&quot;/tags/pandoc.html&quot;&gt;pandoc&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;markdown&apos;.&quot; href=&quot;/tags/markdown.html&quot;&gt;markdown&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;chinese&apos;.&quot; href=&quot;/tags/chinese.html&quot;&gt;chinese&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;japanese&apos;.&quot; href=&quot;/tags/japanese.html&quot;&gt;japanese&lt;/a&gt;
    
&lt;/div&gt;

&lt;h2&gt;The motivation&lt;/h2&gt;
&lt;p&gt;Chinese and Japanese languages use ideograms in their written forms, but sometimes it is useful to show the reader how those ideograms should be pronounced. To do that, phonetic systems like &lt;strong&gt;{汉语|hànyǔ}{拼音|pīnyīn}&lt;/strong&gt; and &lt;strong&gt;{振り仮名|fu|ri|ga|na}&lt;/strong&gt; are used.&lt;/p&gt;
&lt;p&gt;In html documents we can use &lt;code&gt;ruby&lt;/code&gt; elements to show phonetic representation above the ideograms, like in the following example:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Code&lt;/th&gt;&lt;th&gt;Expected Result&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;我喜欢&amp;lt;ruby&amp;gt;汉&amp;lt;rt&amp;gt;hàn&amp;lt;/rt&amp;gt;字&amp;lt;rt&amp;gt;zì&amp;lt;/rt&amp;gt;&amp;lt;/ruby&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;中国&lt;ruby&gt;汉&lt;rt&gt;hàn&lt;/rt&gt;字&lt;rt&gt;zì&lt;/rt&gt;&lt;/ruby&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The problem is that writing text using &lt;code&gt;ruby&lt;/code&gt; elements it is tedious and error prone. We prefer writing something like the following examples:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Code&lt;/th&gt;&lt;th&gt;Expected Result&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;`我喜欢{汉字&lt;/td&gt;&lt;td&gt;hàn&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;`我喜欢{汉字&lt;/td&gt;&lt;td&gt;hànzì}`&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;`我喜欢{汉字&lt;/td&gt;&lt;td&gt;}`&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;`我喜欢{汉字&lt;/td&gt;&lt;td&gt;hà&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;我喜欢{汉字}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;我喜欢{汉字}&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;`我喜欢{&lt;/td&gt;&lt;td&gt;hànzì}`&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;`我喜欢{&lt;/td&gt;&lt;td&gt;}`&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The rest of the post explains how to handle those custom markdown expressions to produce the &lt;code&gt;ruby&lt;/code&gt; elements without writing them by hand. I implemented this code in &lt;strong&gt;Haskell&lt;/strong&gt; language as a &lt;strong&gt;Pandoc&lt;/strong&gt; filter, because this blog uses &lt;strong&gt;Hakyll&lt;/strong&gt; static generator which uses the &lt;strong&gt;Pandoc&lt;/strong&gt; library.&lt;/p&gt;
&lt;h2&gt;Document representation&lt;/h2&gt;
&lt;p&gt;Pandoc uses a custom datatype to represent in an uniform way the multiple types of contents it can handle. That type is called &lt;code&gt;Pandoc&lt;/code&gt; and basically contains a tree-like structure formed by different nodes. We are interested in processing only nodes which are specific instances of the &lt;code&gt;Inline&lt;/code&gt; type, because they contain the pieces of text we want to modify.&lt;/p&gt;
&lt;p&gt;We have a piece of code which process the provided Pandoc data structure.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;transformCustomMarkdownRuby :: Pandoc -&amp;gt; Pandoc
transformCustomMarkdownRuby = walk handleInline
  where
    handleInline :: Inline -&amp;gt; Inline
    handleInline (Str s) = case (parse markdownRuby &quot;&quot; s) of
        (Left _)     -&amp;gt; Str s
        (Right rubies) -&amp;gt; RawInline (Format &quot;html&quot;) (rubiesToHtml rubies)
    handleInline x       = x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key point in this code is the pattern matching over the &lt;code&gt;Inline&lt;/code&gt; type, specifically over the &lt;code&gt;Str&lt;/code&gt; instances. We use the &lt;code&gt;walk&lt;/code&gt; function to process all the matched nodes recursively, leaving the other ones untouched. A &lt;code&gt;RawInline&lt;/code&gt; instance is generated when ruby tags are found, otherwise the original &lt;code&gt;Str&lt;/code&gt; instance is preserved.&lt;/p&gt;
&lt;h2&gt;Text processing&lt;/h2&gt;
&lt;p&gt;When we have a candidate to be modified, it is necessary to verify if it follows the correct syntax, so we can parse it to extract the data and render it the way we want.&lt;/p&gt;
&lt;p&gt;Now, here we have the code which does main work:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;markdownRuby :: Parsec String () [(String,[(String,String)],String)]
markdownRuby = many $ choice [try ruby, fallback]
  where
    ruby :: Parsec String () (String,[(String,String)],String)
    ruby = (,,) -- (openingText,rubyPairs,closingText)
        &amp;lt;$&amp;gt; (many $ noneOf &quot;{&quot;)
        &amp;lt;*&amp;gt; between (char &apos;{&apos;) (char &apos;}&apos;) markdownRubyPairs
        &amp;lt;*&amp;gt; (many $ noneOf &quot;{&quot;)
    fallback :: Parsec String () (String,[(String,String)],String)
    fallback = (,,) -- (openingText,rubyPairs,closingText)
        &amp;lt;$&amp;gt; (many1 $ anyChar)
        &amp;lt;*&amp;gt; pure []
        &amp;lt;*&amp;gt; pure &quot;&quot;
markdownRubyPairs :: Parsec String () [(String,String)]
markdownRubyPairs = do
    elems &amp;lt;- taggedElems
    tags  &amp;lt;- many1 rubyTag
    let sameLen = length elems == length tags
        matchingPairs = zip elems tags
        singlePair = [(mconcat elems,intercalate &quot;|&quot; tags)]
    pure $ if sameLen then matchingPairs else singlePair
  where
    taggedElems :: Parsec String () [String]
    taggedElems = fmap (fmap pure) (many (noneOf &quot;|}&quot;))
    rubyTag = char &apos;|&apos; *&amp;gt; (many $ noneOf &quot;|}&quot;)
rubyToHtml :: (String,[(String,String)],String) -&amp;gt; String
rubyToHtml (prev,pairs,next) = prev &amp;lt;&amp;gt; pairsToHtml pairs &amp;lt;&amp;gt; next 
  where
    pairsToHtml [] = &quot;&quot;
    pairsToHtml ps = (wrap . mconcat . fmap pairToHtml) ps
    pairToHtml (&quot;&quot;,&quot;&quot;) = &quot;&quot;
    pairToHtml (elem,tag) = elem &amp;lt;&amp;gt; &quot;&amp;lt;rt&amp;gt;&quot; &amp;lt;&amp;gt; tag &amp;lt;&amp;gt; &quot;&amp;lt;/rt&amp;gt;&quot;
    wrap x = &quot;&amp;lt;ruby&amp;gt;&quot; &amp;lt;&amp;gt; x &amp;lt;&amp;gt; &quot;&amp;lt;/ruby&amp;gt;&quot;
rubiesToHtml :: [(String,[(String,String)],String)] -&amp;gt; String
rubiesToHtml = mconcat . fmap rubyToHtml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are using a library called &lt;code&gt;Parsec&lt;/code&gt;, which provides us tools to easily handle the parsing. This code uses them to separate the text in 3 parts: the text before our target, the target itself, the text after our target. Because our target should be between braces, we use te &lt;code&gt;between&lt;/code&gt; combinator to find it.&lt;/p&gt;
&lt;p&gt;When the target is found, its contents are separated into base elements and their respective ruby tags, so they can be grouped into pairs. It is assumed that the number of elements and tags is equal, otherwise we have to merge them into a single pair to preserve this property.&lt;/p&gt;
&lt;p&gt;Finally, when we have the independent pieces, we can take and arrange them to render the view in the format we like. Pandoc support many formats, but in this case we are using Html.&lt;/p&gt;
&lt;h2&gt;Some caveats&lt;/h2&gt;
&lt;p&gt;The current code doesn&apos;t handle some cases well. I&apos;m still working on it to make it work with markdown tables, formatting inside the tags, and other missing bits.&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
    // This is a self executing function
    var issueId = 2;
    var url = &quot;https://github.com/rainbyte/rainbyte.github.io/issues/&quot; + issueId;
    var api_url = &quot;https://api.github.com/repos/rainbyte/rainbyte.github.io/issues/&quot; + issueId + &quot;/comments&quot;;
    (function() {
        // DOM is already available, now we can handle page elements
        var ghCommentsList = document.getElementById(&quot;gh-comments-list&quot;);

        var request = new XMLHttpRequest();
        request.open(&apos;GET&apos;, api_url, true);
        request.onload = function() {
            if (request.status &gt;= 200 &amp;&amp; request.status &lt; 400) {
                // Request was successful, we can process the raw comments
                var comments = JSON.parse(request.responseText);
                var fragment = document.createDocumentFragment();
                var range = new Range();

                // Render comments section header
                fragment.appendChild(range.createContextualFragment(`
                    &lt;div&gt;
                        &lt;b&gt;Comments section&lt;/b&gt; (visit the &lt;b&gt;&lt;a href=&apos;${url}&apos;&gt;issue&lt;/a&gt;&lt;/b&gt; of this post to add one)
                    &lt;/div&gt;
                `));

                // Render view of each comment
                comments.forEach(comment =&gt; {
                    var date = new Date(comment.created_at);
                    var renderedComment = range.createContextualFragment(`
                        &lt;div class=&apos;gh-comment&apos;&gt;
                            &lt;div class=&apos;gh-comment-header&apos;&gt;
                                &lt;img src=&apos;${comment.user.avatar_url}&apos;&gt;
                                &lt;div&gt;
                                    &lt;b&gt;&lt;a href=&apos;${comment.user.html_url}&apos;&gt;${comment.user.login}&lt;/a&gt;&lt;/b&gt; posted at &lt;em&gt;${date.toDateString()}&lt;/em&gt;
                                &lt;/div&gt;
                            &lt;/div&gt;
                            &lt;div class=&apos;gh-comment-body&apos;&gt;
                                ${comment.body}
                            &lt;/div&gt;
                        &lt;/div&gt;
                    `);
                    fragment.appendChild(renderedComment);
                });

                // Make changes visible by adding rendered nodes
                ghCommentsList.append(fragment);
            } else {
                // Request reached the target server, but it returned an error
                ghCommentsList.append(&quot;Comments are not available now.&quot;);
            }
        };
        request.onerror = function() {
            // There was a connection error of some sort
            ghCommentsList.append(&quot;Comments are not available now.&quot;);
        };
        request.send();
    })();
&lt;/script&gt;
</summary></entry><entry><title>Use GitHub API to implement comments feature</title><id>https://rainbyte.net.ar/posts/181113-01-use-github-api-to-implement-comments.html</id><updated>2018-11-16T22:48:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/181113-01-use-github-api-to-implement-comments.html" rel="alternate"/><published>2018-11-16T22:48:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2018-11-16 22:48:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;blog&apos;.&quot; href=&quot;/tags/blog.html&quot;&gt;blog&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;The comments section of this blog is implemented via standard GitHub issues and given that GitHub provides an API to access the public information of a repository, we can use it. If we have a repository with issues already created, we can access the comments of a certain issue using an URL like this one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-default&quot;&gt;https://api.github.com/repos/${username}/${repository}/issues/${issueId}/comments
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using that endpoint the API provides us the comments as a list of Javascript objects, each one being similar to this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;{
    &quot;body&quot;: &quot;comment text&quot;,
    &quot;created_at&quot;: &quot;when was the comment published&quot;,
    &quot;user: {
        &quot;avatar_url&quot;: &quot;user image location&quot;,
        &quot;html_url&quot;: &quot;user profile location&quot;,
        &quot;login&quot;: &quot;user nickname&quot;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course there are much more fields available, but these ones are representative enough and using them we can write some Javascript code to render the comments HTML view. This is the code used in this blog to render comments below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;var issueId = $commentsIssue$;
var url = &quot;https://github.com/rainbyte/rainbyte.github.io/issues/&quot; + issueId;
var api_url = &quot;https://api.github.com/repos/rainbyte/rainbyte.github.io/issues/&quot; + issueId + &quot;/comments&quot;;
(function() {
    // DOM is already available, now we can handle page elements
    var ghCommentsList = document.getElementById(&quot;gh-comments-list&quot;);

    var request = new XMLHttpRequest();
    request.open(&apos;GET&apos;, api_url, true);
    request.onload = function() {
        if (request.status &amp;gt;= 200 &amp;amp;&amp;amp; request.status &amp;lt; 400) {
            // Request was successful, we can process the raw comments
            var comments = JSON.parse(request.responseText);
            var fragment = document.createDocumentFragment();
            var range = new Range();

            // Render comments section header
            fragment.appendChild(range.createContextualFragment(`
                &amp;lt;div&amp;gt;
                    &amp;lt;b&amp;gt;Comments section&amp;lt;/b&amp;gt; (visit the &amp;lt;b&amp;gt;&amp;lt;a href=&apos;${url}&apos;&amp;gt;issue&amp;lt;/a&amp;gt;&amp;lt;/b&amp;gt; of this post to add one)
                &amp;lt;/div&amp;gt;
            `));

            // Render view of each comment
            comments.forEach(comment =&amp;gt; {
                var date = new Date(comment.created_at);
                var renderedComment = range.createContextualFragment(`
                    &amp;lt;div class=&apos;gh-comment&apos;&amp;gt;
                        &amp;lt;div class=&apos;gh-comment-header&apos;&amp;gt;
                            &amp;lt;img src=&apos;$${comment.user.avatar_url}&apos;&amp;gt;
                            &amp;lt;div&amp;gt;
                                &amp;lt;b&amp;gt;&amp;lt;a href=&apos;${comment.user.html_url}&apos;&amp;gt;${comment.user.login}&amp;lt;/a&amp;gt;&amp;lt;/b&amp;gt; posted at &amp;lt;em&amp;gt;${date.toDateString()}&amp;lt;/em&amp;gt;
                            &amp;lt;/div&amp;gt;
                        &amp;lt;/div&amp;gt;
                        &amp;lt;div class=&apos;gh-comment-body&apos;&amp;gt;
                            $${comment.body}
                        &amp;lt;/div&amp;gt;
                    &amp;lt;/div&amp;gt;
                `);
                fragment.appendChild(renderedComment);
            });

            // Make changes visible by adding rendered nodes
            ghCommentsList.append(fragment);
        } else {
            // Request reached the target server, but it returned an error
            ghCommentsList.append(&quot;Comments are not available now.&quot;);
        }
    };
    request.onerror = function() {
        // There was a connection error of some sort
        ghCommentsList.append(&quot;Comments are not available now.&quot;);
    };
    request.send();
})();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If code is working ok, you can see a comments section under this text and add a new comment following the provided link.&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
    // This is a self executing function
    var issueId = 1;
    var url = &quot;https://github.com/rainbyte/rainbyte.github.io/issues/&quot; + issueId;
    var api_url = &quot;https://api.github.com/repos/rainbyte/rainbyte.github.io/issues/&quot; + issueId + &quot;/comments&quot;;
    (function() {
        // DOM is already available, now we can handle page elements
        var ghCommentsList = document.getElementById(&quot;gh-comments-list&quot;);

        var request = new XMLHttpRequest();
        request.open(&apos;GET&apos;, api_url, true);
        request.onload = function() {
            if (request.status &gt;= 200 &amp;&amp; request.status &lt; 400) {
                // Request was successful, we can process the raw comments
                var comments = JSON.parse(request.responseText);
                var fragment = document.createDocumentFragment();
                var range = new Range();

                // Render comments section header
                fragment.appendChild(range.createContextualFragment(`
                    &lt;div&gt;
                        &lt;b&gt;Comments section&lt;/b&gt; (visit the &lt;b&gt;&lt;a href=&apos;${url}&apos;&gt;issue&lt;/a&gt;&lt;/b&gt; of this post to add one)
                    &lt;/div&gt;
                `));

                // Render view of each comment
                comments.forEach(comment =&gt; {
                    var date = new Date(comment.created_at);
                    var renderedComment = range.createContextualFragment(`
                        &lt;div class=&apos;gh-comment&apos;&gt;
                            &lt;div class=&apos;gh-comment-header&apos;&gt;
                                &lt;img src=&apos;${comment.user.avatar_url}&apos;&gt;
                                &lt;div&gt;
                                    &lt;b&gt;&lt;a href=&apos;${comment.user.html_url}&apos;&gt;${comment.user.login}&lt;/a&gt;&lt;/b&gt; posted at &lt;em&gt;${date.toDateString()}&lt;/em&gt;
                                &lt;/div&gt;
                            &lt;/div&gt;
                            &lt;div class=&apos;gh-comment-body&apos;&gt;
                                ${comment.body}
                            &lt;/div&gt;
                        &lt;/div&gt;
                    `);
                    fragment.appendChild(renderedComment);
                });

                // Make changes visible by adding rendered nodes
                ghCommentsList.append(fragment);
            } else {
                // Request reached the target server, but it returned an error
                ghCommentsList.append(&quot;Comments are not available now.&quot;);
            }
        };
        request.onerror = function() {
            // There was a connection error of some sort
            ghCommentsList.append(&quot;Comments are not available now.&quot;);
        };
        request.send();
    })();
&lt;/script&gt;
</summary></entry><entry><title>Set terminal tab title using fish shell</title><id>https://rainbyte.net.ar/posts/181112-01-set-title-with-fish.html</id><updated>2018-11-12T07:28:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/181112-01-set-title-with-fish.html" rel="alternate"/><published>2018-11-12T07:28:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2018-11-12 07:28:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;fish&apos;.&quot; href=&quot;/tags/fish.html&quot;&gt;fish&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;shell&apos;.&quot; href=&quot;/tags/shell.html&quot;&gt;shell&lt;/a&gt;
    
&lt;/div&gt;

&lt;h2&gt;Approach #1: setting the title by hand&lt;/h2&gt;
&lt;p&gt;When there are many terminal tabs opened, it is really useful to give them meaninful names.&lt;/p&gt;
&lt;p&gt;Fish shell allows setting the current tab&apos;s title creating a &lt;code&gt;fish_title&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;If we want to name our tab &lt;code&gt;FOO&lt;/code&gt;, we could just write this in the terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;function fish_title
    echo &quot;FOO&quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After entering the code, the function will be exported and the new title will be used.&lt;/p&gt;
&lt;p&gt;The problem with this way is that writing the function each time is tedious.&lt;/p&gt;
&lt;p&gt;There is an easy way to overcome this problem.&lt;/p&gt;
&lt;h2&gt;Approach #2: using a helper function&lt;/h2&gt;
&lt;p&gt;We could write a helper which export the &lt;code&gt;fish_title&lt;/code&gt; function for us.&lt;/p&gt;
&lt;p&gt;I call this helper &lt;code&gt;set_title&lt;/code&gt;, but other name could be used as well.&lt;/p&gt;
&lt;p&gt;First we need to write the helper function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;function set_title
    set -l title $argv[1]
    function fish_title --inherit-variable title
        echo &quot;$title&quot;
    end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can test it, eg. to name our tab &lt;code&gt;BAR&lt;/code&gt; we could call it this way: &lt;code&gt;set_title BAR&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Finally, to save the function persistently, we execute this: &lt;code&gt;funcsave set_title&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;How does it work?&lt;/h2&gt;
&lt;p&gt;Each time we execute &lt;code&gt;set_title&lt;/code&gt;, it will re-export the &lt;code&gt;fish_title&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;We need to make the &lt;em&gt;title&lt;/em&gt; variable available inside &lt;code&gt;fish_title&lt;/code&gt; scope.&lt;/p&gt;
&lt;p&gt;The trick is using the &lt;code&gt;--inherit-variable&lt;/code&gt; option, which will solve this for us.&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>Programación de GPU en Haskell usando GPipe - Parte 2</title><id>https://rainbyte.net.ar/posts/160501-01-gpipe-part-02.html</id><updated>2016-10-26T07:29:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/160501-01-gpipe-part-02.html" rel="alternate"/><published>2016-10-26T07:29:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2016-10-26 07:29:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;gpipe&apos;.&quot; href=&quot;/tags/gpipe.html&quot;&gt;gpipe&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;gpu&apos;.&quot; href=&quot;/tags/gpu.html&quot;&gt;gpu&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;haskell&apos;.&quot; href=&quot;/tags/haskell.html&quot;&gt;haskell&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;opengl&apos;.&quot; href=&quot;/tags/opengl.html&quot;&gt;opengl&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;Nota: estas leyendo la traducción al castellano de una serie de tutoriales en ingles sobre GPipe; la versión original, escrita por Tobias Bexelius (creador de GPipe), se encuentra &lt;a href=&quot;http://tobbebex.blogspot.com.ar/2015/09/gpu-programming-in-haskell-using-gpipe_11.html&quot;&gt;aqui&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/160426-01-gpipe-part-01.html&quot;&gt;&amp;lt; Episodio previo: Hello triangle&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;¡Bienvenido nuevamente! En la ultima parte obtuviste tu primer triangulo mediante GPipe. Esta vez vamos a examinar &lt;code&gt;Buffer&lt;/code&gt; y &lt;code&gt;PrimitiveArray&lt;/code&gt; con más detalle.&lt;/p&gt;
&lt;h2&gt;Buffers&lt;/h2&gt;
&lt;p&gt;En el ejemplo &quot;Hello world&quot; que hicimos la ultima vez, usamos un &lt;code&gt;Buffer&lt;/code&gt; para almacenar las posiciones y colores del triangulo. A partir de este buffer, creamos un &lt;code&gt;PrimitiveArray&lt;/code&gt; que enviamos al shader. Más adelante vamos a ver que un &lt;code&gt;Buffer&lt;/code&gt; puede ser usado también para otras cosas.&lt;/p&gt;
&lt;p&gt;Un &lt;code&gt;Buffer&lt;/code&gt; en GPipe es un array de datos que esta almacenado en la GPU. Es mutable, así como &lt;code&gt;IOArray&lt;/code&gt; o &lt;code&gt;STArray&lt;/code&gt;, y así como aquellos también vive en una monada, en este caso la monada &lt;code&gt;ContextT&lt;/code&gt;. Veamos primero la función que se encarga de crear buffers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;newBuffer :: (MonadIO m, BufferFormat b) =&amp;gt; Int -&amp;gt; ContextT w os f m (Buffer os b)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Un buffer tiene tipo &lt;code&gt;Buffer os b&lt;/code&gt;, donde &lt;code&gt;os&lt;/code&gt; es el mismo que el de &lt;code&gt;ContextT&lt;/code&gt;. Como puedes recordar desde la ultima vez, este parámetro de tipo &lt;code&gt;os&lt;/code&gt; es usado para evitar que los objetos asociados a un contexto puedan escapar de la monada, y &lt;code&gt;Buffer&lt;/code&gt; es uno de esos objetos.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;newBuffer&lt;/code&gt; solo toma un argumento: el numero de elementos a crear en el buffer. Un buffer tiene elementos mutables, pero el numero de elementos es inmutable. El tipo de los elementos del buffer se denota con &lt;code&gt;b&lt;/code&gt;, y puedes ver que este &lt;code&gt;b&lt;/code&gt; esta delimitado por el typeclass &lt;code&gt;BufferFormat b&lt;/code&gt;. Antes de mostrarte ese typeclass, miremos la función que vas a usar para llenar el buffer con datos desde el lado de la CPU:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;writeBuffer :: MonadIO m =&amp;gt; Buffer os b -&amp;gt; BufferStartPos -&amp;gt; [HostFormat b] -&amp;gt; ContextT w os f m ()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Esta función toma un buffer para escribir y una posición de inicio con indice basado en cero, nada extraño en esto, pero luego toma una lista de &lt;code&gt;HostFormat b&lt;/code&gt;... ¿Que ocurre con esto? Los contenidos de un buffer no tienen la misma representación en el host que en el buffer, el cual vive en la GPU (desde ahora voy a usar el termino &lt;strong&gt;host&lt;/strong&gt; cuando me refiero al entorno normal de Haskell que vive en la CPU, en contraposición al mundo de la GPU). &lt;code&gt;HostFormat b&lt;/code&gt; es un tipo al typeclass &lt;code&gt;BufferFormat b&lt;/code&gt;. Miremos ese typeclass:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;class BufferFormat f where
  type HostFormat f
  toBuffer :: ToBuffer (HostFormat f) f
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;El único propósito de esta clase, es proveer una representación para el tipo de los elementos del buffer en el host, así como una conversión de la representación del host a la del buffer. Aquí hay algunos ejemplos de instancias de esta clase, y sus representaciones en el host:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;f&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;HostFormat f&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;B Float&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Float&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;B Int32&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Int32&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;B Word32&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Word32&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;B2 Float&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;V2 Float&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;B2 Int32&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;V2 Int32&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;B2 Word32&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;V2 Word32&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;B2 Int16&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;V2 Int16&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;B2 Word16&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;V2 Word16&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;(a, b)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;(HostFormat a, HostFormat b)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;V2 a&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;V2 (HostFormat a)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Hay muchas más instancias, incluyendo &lt;code&gt;B3&lt;/code&gt;, &lt;code&gt;B4&lt;/code&gt; y tuplas mas grandes. Mira la lista completa &lt;a href=&quot;https://hackage.haskell.org/package/GPipe-2.0.1/docs/Graphics-GPipe-Buffer.html#t:BufferFormat&quot;&gt;en hackage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Un &lt;code&gt;Float&lt;/code&gt; en el host se convertirá &lt;code&gt;B Float&lt;/code&gt; en el &lt;code&gt;Buffer&lt;/code&gt;. &lt;code&gt;B a&lt;/code&gt; es un tipo opaco de cual no puedes inspeccionar su valor o hacer ningún calculo, por ej. no hay instancia de &lt;code&gt;Num&lt;/code&gt; para &lt;code&gt;B Float&lt;/code&gt;. Para &lt;code&gt;Buffer&lt;/code&gt; no se expone una manera de aplicar funciones en sus elementos de ninguna manera (por ej. &lt;code&gt;Buffer&lt;/code&gt; no posee instancia del typeclass &lt;code&gt;Functor&lt;/code&gt;), pero vamos a crear pronto un &lt;code&gt;VertexArray&lt;/code&gt; a partir de nuestro &lt;code&gt;Buffer&lt;/code&gt; y entonces será distinto.&lt;/p&gt;
&lt;p&gt;GPipe también define los tipos &lt;code&gt;B2 a&lt;/code&gt;, &lt;code&gt;B3 a&lt;/code&gt; y &lt;code&gt;B4 a&lt;/code&gt;. Para un conjunto selecto de &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;B2 a&lt;/code&gt; es la representación en el buffer de un &lt;code&gt;V2 a&lt;/code&gt; en el host. &lt;code&gt;V2 a&lt;/code&gt; es también una instancia de &lt;code&gt;BufferFormat&lt;/code&gt; con &lt;code&gt;V2 (HostFormat a)&lt;/code&gt; como representación en el host, lo cual significa que tanto &lt;code&gt;V2 (B Float)&lt;/code&gt; como &lt;code&gt;B2 Float&lt;/code&gt; tienen la misma representación en el host: &lt;code&gt;V2 Float&lt;/code&gt;. Ambos formatos de buffer tienen el mismo tamaño e incluso disposición interna, pero &lt;code&gt;B2 Float&lt;/code&gt; puede ser usado de manera más eficiente como vamos a ver luego.  Por esta razón, siempre intenta usar tipos B en vez de tipos V en los buffers, cuando sea posible. Entonces, ¿porque hay una instancia de &lt;code&gt;BufferFormat&lt;/code&gt; para &lt;code&gt;V2&lt;/code&gt;? El caso de uso principal es el de las matrices, por ej. &lt;code&gt;V4 (V4 Float)&lt;/code&gt; en el host puede almacenarse en un buffer como &lt;code&gt;V4 (B4 Float)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Otra cosa interesante que puedes haber notado al estudiar la lista de instancias de &lt;code&gt;BufferFormat&lt;/code&gt;, es que hay instancias de &lt;code&gt;B2 Int16&lt;/code&gt; y &lt;code&gt;B2 Word16&lt;/code&gt;, pero no de &lt;code&gt;B Int16&lt;/code&gt; ni &lt;code&gt;B Word16&lt;/code&gt;. Esto es porque los atributos de los vértices tienen que estar alineados a 4 bytes en algunas piezas de hardware, y GPipe respeta esto en sus tipos de datos. &lt;code&gt;Int16&lt;/code&gt; y &lt;code&gt;Word16&lt;/code&gt; son ambos de 2 bytes, así que necesitas tener un vector de al menos dos de ellos. Hay instancias de &lt;code&gt;B3 Int16&lt;/code&gt; y &lt;code&gt;B3 Word16&lt;/code&gt;, pero estas poseen un relleno (padding) de 2 bytes extra. La motivación para esto es que siempre podrías usar &lt;code&gt;B Int32&lt;/code&gt; en vez de &lt;code&gt;B Int16&lt;/code&gt; si existiese, funcionarían con los mismos shaders y serian del mismo tamaño de todas formas si agregamos el relleno para el segundo. Por otra parte, un &lt;code&gt;B3 Int32&lt;/code&gt; toma 12 bytes mientras que un &lt;code&gt;B3 Int16&lt;/code&gt; con relleno incluido solo ocupa 8 bytes, así que hay un caso distintivo para este ultimo. Un &lt;code&gt;B4 Int16&lt;/code&gt; también utiliza 8 bytes, pero no funcionaria con los mismos shaders, como va a ser evidente en la siguiente parte de este tutorial.&lt;/p&gt;
&lt;p&gt;Ahora miremos el miembro &lt;code&gt;toBuffer&lt;/code&gt; del typeclass &lt;code&gt;BufferFormat&lt;/code&gt;. Posee el tipo &lt;code&gt;ToBuffer (HostFormat f) f&lt;/code&gt;. &lt;code&gt;ToBuffer&lt;/code&gt; es algo llamado &lt;strong&gt;arrow&lt;/strong&gt; en Haskell. Es como una función (en este caso &lt;code&gt;HostFormat f -&amp;gt; f&lt;/code&gt;), pero más general. Echemos un vistazo a la instancia &lt;code&gt;BufferFormat (a, b)&lt;/code&gt; como ejemplo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;{-# LANGUAGE Arrows #-}

instance (BufferFormat a, BufferFormat b) =&amp;gt; BufferFormat (a, b) where
  type HostFormat (a,b) = (HostFormat a, HostFormat b)
  toBuffer = proc ~(a, b) -&amp;gt; do
                a&apos; &amp;lt;- toBuffer -&amp;lt; a
                b&apos; &amp;lt;- toBuffer -&amp;lt; b
                returnA -&amp;lt; (a&apos;, b&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;La notación arrow casi se parece a un lambda (usando el keyword especial &lt;code&gt;proc&lt;/code&gt;) retornando una acción monadica. Pero no es una monada. La mayor diferencia con una monada es que no puede seleccionar una acción basándose en los valores de retorno del arrow. Es por esto que las acciones de un arrow poseen una cola (&lt;code&gt;-&amp;lt;&lt;/code&gt;); cualquier cosa entre las partes &lt;code&gt;&amp;lt;-&lt;/code&gt; y &lt;code&gt;-&amp;lt;&lt;/code&gt; de un arrow, no puede referenciar nada fuera de ellas (&lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;a&apos;&lt;/code&gt;, &lt;code&gt;b&apos;&lt;/code&gt; en este caso). Esto obliga a que toda invocación a &lt;code&gt;toBuffer&lt;/code&gt; deba ir a través de la misma serie de acciones de arrow, independientemente de los valores de entrada reales. Otro requerimiento adicional que tiene GPipe, es que necesita ser capaz de producir valores de forma lazy, es por ello el tilde (&lt;code&gt;~&lt;/code&gt;) en el patrón &lt;code&gt;proc&lt;/code&gt;. Las únicas acciones del arrow &lt;code&gt;ToBuffer&lt;/code&gt; que GPipe define para usar en tu propia implementación de &lt;code&gt;toBuffer&lt;/code&gt;, son los métodos &lt;code&gt;toBuffer&lt;/code&gt; de otras instancias. Vas a ver aparecer este patrón, donde un arrow es usado para definir la conversión entre dos dominios, en varios lugares de GPipe a medida continuemos con el tutorial.&lt;/p&gt;
&lt;h2&gt;Arrays de vértices&lt;/h2&gt;
&lt;p&gt;Bueno, ¡ahora eres un experto en buffers! Vamos a darles algún uso:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;newVertexArray :: Buffer os a -&amp;gt; Render os f (VertexArray t a)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ejecutas esta función en una monada &lt;code&gt;Render&lt;/code&gt; para crear un &lt;code&gt;VertexArray t a&lt;/code&gt;. Un array de vértices es como la vista de un buffer, y &lt;code&gt;newVertexArray&lt;/code&gt; no copia ningún dato. Ya que operamos dentro de la monada &lt;code&gt;Render&lt;/code&gt; (que es ejecutada por la función render, la cual no permite valores de retorno), y un &lt;code&gt;Buffer&lt;/code&gt; solo puede ser modificado fuera de esta monada (en la monada &lt;code&gt;ContextT&lt;/code&gt;), conceptualmente podrías pensar a &lt;code&gt;VertexArray&lt;/code&gt; como una copia del &lt;code&gt;Buffer&lt;/code&gt;. No lo es realmente, pero puedes tratarlo como una.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;VertexArray t a&lt;/code&gt; es un array de vértices donde cada vértice es un elemento de tipo &lt;code&gt;a&lt;/code&gt;, que es el mismo tipo de los elementos del &lt;code&gt;Buffer&lt;/code&gt; a partir del cual lo creaste. No te preocupes por el parámetro &lt;code&gt;T&lt;/code&gt; por ahora, vamos a llegar a eso en un momento. El &lt;code&gt;VertexArray&lt;/code&gt; posee tantos vértices como elementos pertenecientes al &lt;code&gt;Buffer&lt;/code&gt; que lo origina, pero en contraste a este ultimo, puedes recortar un &lt;code&gt;VertexArray&lt;/code&gt; usando las funciones &lt;code&gt;dropVertices&lt;/code&gt; o &lt;code&gt;takeVertices&lt;/code&gt;. Estas funcionan exactamente como &lt;code&gt;drop&lt;/code&gt; o &lt;code&gt;take&lt;/code&gt; trabajan sobre listas normales:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;takeVertices :: Int -&amp;gt; VertexArray t a -&amp;gt; VertexArray t a Source
dropVertices :: Int -&amp;gt; VertexArray () a -&amp;gt; VertexArray t a Source
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;VertexArray&lt;/code&gt; también tiene una instancia de &lt;code&gt;Functor&lt;/code&gt;, la cual permite aplicar &lt;code&gt;fmap&lt;/code&gt; sobre los vértices. ¡Aqui es donde la opacidad de los tipos B entran en juego! Ahora que puedes hacer cosas con tus valores B, vas a notar que las opciones son algo limitadas. Puedes simplemente agarrar elementos de estructuras como tuplas y/o construir nuevas estructuras con los valores que posees. A pesar de esto, hay un par de funciones que operan sobre valores B que puedes usar aquí:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;toB22 :: forall a. (Storable a, BufferFormat (B2 a)) =&amp;gt; B4 a -&amp;gt; (B2 a, B2 a)
toB3 :: forall a. (Storable a, BufferFormat (B3 a)) =&amp;gt; B4 a -&amp;gt; B3 a
toB21 :: forall a. (Storable a, BufferFormat (B a)) =&amp;gt; B3 a -&amp;gt; (B2 a, B a)
toB12 :: forall a. (Storable a, BufferFormat (B a)) =&amp;gt; B3 a -&amp;gt; (B a, B2 a)
toB11 :: forall a. (Storable a, BufferFormat (B a)) =&amp;gt; B2 a -&amp;gt; (B a, B a)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Estas permiten separar vectores B en partes mas pequeñas. Fijate que de todos modos no hay funciones que puedan combinarlas nuevamente.&lt;/p&gt;
&lt;p&gt;Puedes también hacer comprimir (zip) dos &lt;code&gt;VertexArray&lt;/code&gt; juntos, con la función &lt;code&gt;zipVertices&lt;/code&gt;, que funciona exactamente como &lt;code&gt;zipWith&lt;/code&gt; para listas normales; provees una función para combinar los elementos de ambos argumentos &lt;code&gt;VertexArray&lt;/code&gt; y el resultante sera del tamaño del más pequeño de ambos arrays:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;zipVertices :: (a -&amp;gt; b -&amp;gt; c) -&amp;gt; VertexArray t a -&amp;gt; VertexArray t&apos; b -&amp;gt; VertexArray (Combine t t&apos;) c
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;(Nuevamente, no te preocupes por el extraño primer parámetro en el VertexArray retornado, lo explicaré más adelante)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Comprimir arrays de vértices es lo que se corresponde con usar arrays no-intercalados (non-interleaved) en OpenGL, mientras que un array de vértices desde un solo buffer de un tipo de elementos compuestos (así como una tupla de dos valores B) corresponde a arrays intercalados (interleaved). ¡Esta es solo la manera funcional y type safe de hacerlo!&lt;/p&gt;
&lt;h2&gt;Arrays de primitivas&lt;/h2&gt;
&lt;p&gt;Ahora que haz recortado (trim), comprimido (zip) y mapeado (fmap) tus arrays de vértices a la perfección, es hora de crear un array de primitivas. La manera más simple de crear uno es con esta función:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;toPrimitiveArray :: PrimitiveTopology p -&amp;gt; VertexArray () a -&amp;gt; PrimitiveArray p a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Siempre vas a necesitar una topología de primitivas, ademas de tu array de vértices, para crear un &lt;code&gt;PrimitiveArray&lt;/code&gt;. La topología de primitivas denota como los vértices deben conectarse para formar primitivas, y es uno de estos constructores:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;data PrimitiveTopology p where
  TriangleList :: PrimitiveTopology Triangles
  TriangleStrip :: PrimitiveTopology Triangles
  TriangleFan :: PrimitiveTopology Triangles
  LineList :: PrimitiveTopology Lines
  LineStrip :: PrimitiveTopology Lines
  LineLoop :: PrimitiveTopology Lines
  PointList :: PrimitiveTopology Points
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;En la mayoría de los casos vas a trabajar con triángulos. Veamos como se ven las tres topologias de triángulos:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/gpipe-part-02-triangle-topologies.png&quot; alt=&quot;(a) - TriangleStrip, (b) - TriangleFan, (c) - TriangleList (Image courtesy of OpenGL specification by Khronos)&quot; /&gt;&lt;/p&gt;
&lt;p&gt;En un &lt;code&gt;TriangleStrip&lt;/code&gt;, cada vértice forma un triangulo con los dos vértices previos, alternando el camino de los vértices para cada triangulo. Esto significa que el primer triangulo es formado por los vértices 1-2-3 en ese orden, el siguiente por 2-4-3, luego por 3-4-5, 4-6-5, y así sucesivamente. Para &lt;code&gt;TriangleFan&lt;/code&gt;, cada triangulo es formado por el primer vértice en el array junto con cada dos vértices consecutivos, en ese orden. Para &lt;code&gt;TriangleList&lt;/code&gt;, cada tres vértices simplemente forman un triangulo; no se comparte ningún vértice entre los triángulos.&lt;/p&gt;
&lt;p&gt;Los vértices siempre vienen en orden antihorario para un triangulo de cara orientada hacia el frente (lo cual significa que todos los triángulos en la imagen de arriba, excepto el de más a la derecha, están orientados con cara hacia el fondo; solo como ejemplo de cuan intuitiva puede ser la especificación de OpenGL). La orientación de la cara de un triangulo va a ser importante luego, cuando lo rastericemos, en ese momento podrás elegir solo rasterizar los triángulos de cara hacia el frente o hacia el fondo.&lt;/p&gt;
&lt;p&gt;Los arrays de primitivas no se pueden recortar como los de vértices, pero poseen una instancia de &lt;code&gt;Functor&lt;/code&gt; así que puedes hacer &lt;code&gt;fmap&lt;/code&gt; sobre ellos exactamente como con los arrays de vértices. También tienen una instancia de &lt;code&gt;Monoid&lt;/code&gt;, que permite concatenar dos &lt;code&gt;PrimitiveArray&lt;/code&gt; juntos en uno solo usando &lt;code&gt;mappend&lt;/code&gt;. Esto hace posible crea un &lt;code&gt;PrimitiveArray&lt;/code&gt; conformado por varias tiras de triángulos disjuntas, pero maneras más eficientes de lograrlo serán presentadas en las siguientes dos secciones.&lt;/p&gt;
&lt;h2&gt;Arrays de indices&lt;/h2&gt;
&lt;p&gt;Es común que un vértice sea usado no solo por dos triángulos consecutivos en una tira, sino también por triángulos de otra tira. Seria un desperdicio duplicar para cada tira todos los datos de los vértices compartidos, y por esta razón puedes usar un &lt;code&gt;index array&lt;/code&gt; como reemplazo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;toPrimitiveArrayIndexed :: PrimitiveTopology p -&amp;gt; IndexArray -&amp;gt; VertexArray () a -&amp;gt; PrimitiveArray p a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;En vez de formas primitivas tomando vértices consecutivos en un &lt;code&gt;VertexArray&lt;/code&gt;, esta función va a tomar los indices de un &lt;code&gt;IndexArray&lt;/code&gt; y usarlos para referenciar vértices del &lt;code&gt;VertexArray&lt;/code&gt;. Múltiples elementos en el &lt;code&gt;IndexArray&lt;/code&gt; pueden referirse al mismo vértice. La topología de primitivas funciona de la misma manera para esta función, pero es aplicada al &lt;code&gt;IndexArray&lt;/code&gt;. Por ejemplo, si &lt;code&gt;TriangleStrip&lt;/code&gt; es usado, el primer triangulo es formado por los vértices referenciados por los primeros tres indices, el siguiente esta formado por el segundo, el cuarto y el tercer indice, y así sucesivamente.&lt;/p&gt;
&lt;p&gt;Puedes crear un &lt;code&gt;IndexArray&lt;/code&gt; usando&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;newIndexArray :: forall os f b a. (BufferFormat b, Integral a, IndexFormat b ~ a) =&amp;gt; Buffer os b -&amp;gt; Maybe a -&amp;gt; Render os f IndexArray
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Muy parecido a crear un &lt;code&gt;VertexArray&lt;/code&gt;, pero el tipo de los elementos del &lt;code&gt;Buffer&lt;/code&gt; a partir del cual lo creas, esta también acotado por el siguiente type family:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;type family IndexFormat a where
  IndexFormat (B Word32) = Word32  
  IndexFormat (BPacked Word16) = Word16  
  IndexFormat (BPacked Word8) = Word8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Esto significa que los indices pueden ser &lt;code&gt;Word32&lt;/code&gt;, &lt;code&gt;Word16&lt;/code&gt; o &lt;code&gt;Word8&lt;/code&gt;. ¿Recuerdas que previamente mencioné que todos los tipos de los elementos del buffer necesitaban tener una alineación de 4-bytes? Los arrays de indices realmente &lt;em&gt;requieren&lt;/em&gt; que todos los elementos estén empaquetados, pero todavía soporta indices de tipo &lt;code&gt;Word16&lt;/code&gt; y &lt;code&gt;Word8&lt;/code&gt;. Esto significa que los buffers de estos dos tipos de elementos &lt;em&gt;no pueden&lt;/em&gt; ser usados como arrays de vértices. Esto es por lo que la representación de &lt;code&gt;Word16&lt;/code&gt; y &lt;code&gt;Word8&lt;/code&gt; es &lt;code&gt;BPacked Word16&lt;/code&gt; y &lt;code&gt;BPacked Word8&lt;/code&gt;. Estos funcionan exactamente como sus contrapartes &lt;em&gt;B&lt;/em&gt;, con la excepción de que no hay instancias de &lt;code&gt;VertexInput&lt;/code&gt; para ningun &lt;code&gt;BPacked a&lt;/code&gt;. &lt;code&gt;VertexInput&lt;/code&gt; es el type class usado en la creación de streams de primitivas desde arrays de primitivas, lo cual vamos a usar en la siguiente parte de este tutorial. Como puedes suponer a esta altura, el type family &lt;code&gt;IndexFormat a&lt;/code&gt; evalúa a los mismos tipos que el tipo asociado &lt;code&gt;HostFormat a&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Además de un buffer de indices, &lt;code&gt;newIndexArray&lt;/code&gt; también toma un &lt;code&gt;Maybe a&lt;/code&gt; como argumento. Esto denota un indice opcional llamado &lt;em&gt;primitive restart&lt;/em&gt;, es decir un valor de indice especial, que si es encontrado en el array de indices mientras se procesan las primitivas, señala que la topología actual debe terminar y el siguiente indice es el comienzo de una nueva topología. Esto hace posible tener múltiples tiras de triángulos en un solo &lt;code&gt;IndexArray&lt;/code&gt; con solo separarlos con un indice especial, lo cual es mucho más eficiente que concatenar múltiples &lt;code&gt;PrimitiveStream&lt;/code&gt; usando su instancia de &lt;code&gt;Monoid&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Los arrays de indices pueden ser recortados como cualquier array de vértices, pero siempre usando las funciones &lt;code&gt;takeIndices&lt;/code&gt; y &lt;code&gt;dropIndices&lt;/code&gt;. No poseen instancia de &lt;code&gt;Functor&lt;/code&gt; (lo cual no tiene sentido) ni de &lt;code&gt;Monoid&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Arrays de primitivas instanciados&lt;/h2&gt;
&lt;p&gt;La ultima cosa que voy a mostrarte en este episodio son los &lt;em&gt;arrays de primitivas instanciados&lt;/em&gt;. Imagina que quieres crear una malla de triángulos de un templo, donde tienes muchos pilares idénticos ubicado en fila. En vez de duplicar los triángulos de cada pilar, o hacer un solo array de primitivas para concatenarlo consigo mismo múltiples veces, puedes crear un array de primitivas instanciado. La función de ve así:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;toPrimitiveArrayInstanced :: PrimitiveTopology p -&amp;gt; (a -&amp;gt; b -&amp;gt; c) -&amp;gt; VertexArray () a -&amp;gt; VertexArray t b -&amp;gt; PrimitiveArray p c
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Es muy similar a la función &lt;code&gt;zipVertices&lt;/code&gt; en que toma dos &lt;code&gt;VertexArray&lt;/code&gt; y una función binaria para combinar los vértices de estos arrays, pero &lt;code&gt;toPrimitiveArrayInstanced&lt;/code&gt; no junta los dos arrays. En cambio, va a crear un array de primitivas desde el primer array de vértices para cada vértice del segundo array, y concatenar los resultados. En nuestro ejemplo de los pilares del templo, el primer array contiene entonces la tira para un solo pilar, mientras que el segundo array contiene una posición para instanciar cada pilar, resultado en un array de primitivas donde cada vértice contiene su posición individual dentro del pilar, asi como la posición de la instancia dentro del templo. Necesitarias entonces un shader que combine estas dos posiciones juntas en la posición final. Esta es la manera más eficiente de renderizar múltiples instancias de un mismo objeto.&lt;/p&gt;
&lt;p&gt;Si quieres usar un arrays de primitivas instanciados y array de primitivas indexados al mismo tiempo, hay una función para hacer eso también:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;toPrimitiveArrayIndexedInstanced :: PrimitiveTopology p -&amp;gt; IndexArray -&amp;gt; (a -&amp;gt; b -&amp;gt; c) -&amp;gt; VertexArray () a -&amp;gt; VertexArray t b -&amp;gt; PrimitiveArray p c
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Para hacer la instanciación aun más poderosa, puedes replicar los vértices en un array un numero fijo de veces cada uno y luego comprimirlo con otro array y usar el resultado como instancias en &lt;code&gt;toPrimitiveArrayInstanced&lt;/code&gt;. Por ejemplo, podrías tener un array de vértices con tres diferentes colores, replicar cada color 5 veces, luego comprimirlo con un array de 15 posiciones, y usar esto como instancias de nuestro templo para tener 15 pilares de colores en tres diferentes graduaciones para variar. La función que usarías para hacer esto es:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;replicateEach :: Int -&amp;gt; VertexArray t a -&amp;gt; VertexArray Instances a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Esto va a replicar cada vértice en el array de argumento tantas veces como sea dictado por el primer argumento. Fijate que el tipo de &lt;code&gt;Instances&lt;/code&gt; en el primer parámetro de tipo del resultante &lt;code&gt;VertexArray&lt;/code&gt;. Quizás hayas notado que este parámetro había sido previamente &lt;code&gt;()&lt;/code&gt; o solamente &lt;code&gt;t&lt;/code&gt;. Si este parámetro de &lt;code&gt;VertexArray&lt;/code&gt; es &lt;code&gt;Instances&lt;/code&gt; entonces el &lt;code&gt;VertexArray&lt;/code&gt; solo puede ser usado para instancias, es decir como ultimo argumento en una llamada a &lt;code&gt;toPrimitiveArrayInstanced&lt;/code&gt; o &lt;code&gt;toPrimitiveArrayIndexedInstanced&lt;/code&gt;. Si vas hacia atrás y miras los tipos de las funciones que toman o retornan &lt;code&gt;VertexArray&lt;/code&gt; más arriba, vas a notar que:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;replicateEach&lt;/code&gt; retorna un &lt;code&gt;VertexArray&lt;/code&gt; que debe ser usado como instancia.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dropVertices&lt;/code&gt; no puede ser usado en ningún &lt;code&gt;VertexArray&lt;/code&gt; que deba ser usado como instancia.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zipVertices&lt;/code&gt; retorna un &lt;code&gt;VertexArray&lt;/code&gt; que debe ser usado como instancia si alguno de los arrays de entrada debe ser usado como instancia.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fui un poco injusto ahora, porque esto ultimo no era algo que pudieses notar solo mirando el tipo de la la función, necesitabas esta definición también:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;type family Combine t t&apos; where
  Combine () Instances = Instances  
  Combine Instances () = Instances  
  Combine Instances Instances = Instances  
  Combine () () = ()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cuando tienes tu &lt;code&gt;PrimitiveArray&lt;/code&gt;, la información de tipo ya sea si fue instanciado, indexado o ambos, se ha ido. Esto significa que puedes usar &lt;code&gt;mappend&lt;/code&gt; sobre un array de primitivas instanciado junto con uno no instanciado, y que el shader al cual envías un array de primitivas no le importa si era instanciado o indexado.&lt;/p&gt;
&lt;p&gt;Esta vez no hay ejemplos de código, así que voy a dejar como ejercicio aplicar lo que aprendiste esta vez en el ejemplo de &lt;a href=&quot;(/posts/160426-01-gpipe-part-01.html)&quot;&gt;la parte anterior&lt;/a&gt;. La próxima vez finalmente vamos a abordar &lt;code&gt;Shader&lt;/code&gt;!&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>Programación de GPU en Haskell usando GPipe - Parte 1</title><id>https://rainbyte.net.ar/posts/160426-01-gpipe-part-01.html</id><updated>2016-04-27T03:23:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/160426-01-gpipe-part-01.html" rel="alternate"/><published>2016-04-27T03:23:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2016-04-27 03:23:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;gpipe&apos;.&quot; href=&quot;/tags/gpipe.html&quot;&gt;gpipe&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;gpu&apos;.&quot; href=&quot;/tags/gpu.html&quot;&gt;gpu&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;haskell&apos;.&quot; href=&quot;/tags/haskell.html&quot;&gt;haskell&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;opengl&apos;.&quot; href=&quot;/tags/opengl.html&quot;&gt;opengl&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;Nota: estas leyendo la traducción al castellano de una serie de tutoriales en ingles sobre GPipe; la versión original, escrita por Tobias Bexelius (creador de GPipe), se encuentra &lt;a href=&quot;http://tobbebex.blogspot.com.ar/2015/09/gpu-programming-in-haskell-using-gpipe.html&quot;&gt;aqui&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Bienvenidos a la primera parte de una serie de tutoriales sobre programación de GPU en Haskell! Vamos a usar &lt;a href=&quot;https://hackage.haskell.org/package/GPipe&quot;&gt;GPipe 2.1&lt;/a&gt;, el cual fue &lt;a href=&quot;http://tobbebex.blogspot.se/2015/09/gpipe-is-dead-long-live-gpipe.html&quot;&gt;recientemente publicado&lt;/a&gt;. GPipe 2 es un API funcional basada en OpenGl 3.3, pero este tutorial no requiere conocimiento previo sobre OpenGl, asi que si sabes Haskell (lo cual &lt;em&gt;es&lt;/em&gt; un prerequisito), y alguna vez quisiste aprender programación grafica, ahora es el momento!&lt;/p&gt;
&lt;h2&gt;Hello triangle&lt;/h2&gt;
&lt;p&gt;Comencemos con un pequeño ejemplo, el programa &quot;Hello world!&quot;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;{-# LANGUAGE ScopedTypeVariables, PackageImports, TypeFamilies #-}   
module Main where   
   
import Graphics.GPipe   
import qualified &quot;GPipe-GLFW&quot; Graphics.GPipe.Context.GLFW as GLFW  
import Control.Monad (unless)  
  
main =    
  runContextT GLFW.newContext (ContextFormatColor RGB8) $ do  
    vertexBuffer :: Buffer os (B4 Float, B3 Float) &amp;lt;- newBuffer 3  
    writeBuffer vertexBuffer 0 [ (V4 (-1) 1 0 1, V3 1 0 0)  
                               , (V4 0 (-1) 0 1, V3 0 1 0)  
                               , (V4 1 1 0 1,  V3 0 0 1)  
                               ]  
                        
    shader &amp;lt;- compileShader $ do  
      primitiveStream &amp;lt;- toPrimitiveStream id  
      fragmentStream &amp;lt;- rasterize (const (FrontAndBack, ViewPort (V2 0 0) (V2 500 500), DepthRange 0 1)) primitiveStream   
      drawContextColor (const (ContextColorOption NoBlending (V3 True True True))) fragmentStream  
      
    loop vertexBuffer shader   
    
loop vertexBuffer shader = do    
  render $ do   
    clearContextColor (V3 0 0 0)   
    vertexArray &amp;lt;- newVertexArray vertexBuffer  
    let primitiveArray = toPrimitiveArray TriangleList vertexArray  
    shader primitiveArray   
  swapContextBuffers  
    
  closeRequested &amp;lt;- GLFW.windowShouldClose   
  unless closeRequested $  
    loop vertexBuffer shader 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Como puedes ver en la lista de &lt;code&gt;import&lt;/code&gt;, se requiere un paquete opcional: &lt;a href=&quot;https://hackage.haskell.org/package/GPipe-GLFW&quot;&gt;GPipe-GLFW&lt;/a&gt; (version 1.1 o superior). Este paquete provee la funcionalidad necesaria para crear ventanas, en las cuales GPipe puede dibujar, asi como las funciones para obtener entrada de teclado y mouse. Esta funcionalidad solia ser parte de las versiones anteriores de GPipe pero, ya que muchos querian ser capaces de elegir libremente que gestor de ventanas usar, se movio a su propio paquete. Al momento de escribir este articulo solo existen bindings para GLFW, pero seguramente apareceran otros más.&lt;/p&gt;
&lt;p&gt;Cuando realizas &lt;code&gt;import Graphics.GPipe&lt;/code&gt; tambien obtienes los paquetes &lt;a href=&quot;https://hackage.haskell.org/package/linear&quot;&gt;linear&lt;/a&gt; y &lt;a href=&quot;https://hackage.haskell.org/package/Boolean&quot;&gt;Boolean&lt;/a&gt; completos, ya que son utilizados constantemente en aplicaciones GPipe.&lt;/p&gt;
&lt;p&gt;Ahora estamos listos para compilar (usa &lt;code&gt;-threaded&lt;/code&gt; como parametro para GHC, ya que GPipe-GLFW lo requiere) y ejecutar nuestro programa, el cual nos mostrará un triangulo bastante colorido en la esquina inferior izquierda de la ventana:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/gpipe-part-01-triangle.png&quot; alt=&quot;Un triangulo colorido&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;El contexto&lt;/h2&gt;
&lt;p&gt;Lo primero que hacemos en la función &lt;code&gt;main&lt;/code&gt; es ejecutar &lt;code&gt;runContextT&lt;/code&gt;. Un &lt;em&gt;contexto&lt;/em&gt; posee dos cosas: una &lt;em&gt;ventana&lt;/em&gt;, y un &lt;em&gt;espacio de objetos&lt;/em&gt;. La ventana es donde tus graficos renderizados se mostraran en pantalla, y el espacio de objetos es lo que va a contener todos los datos para la GPU que tu programa define, muy parecido a lo que es un proceso para los datos usados por la CPU. &lt;code&gt;runContextT&lt;/code&gt; crea un nuevo contexto para nostros. Toma tres argumentos: una &lt;em&gt;fabrica&lt;/em&gt;, un &lt;em&gt;formato&lt;/em&gt;, y una &lt;em&gt;acción monadica&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;La fabrica es lo que le damos a GPipe asi sabe que ventana usar. Para utilizar el paquete GPipe-GLFW, que importamos previamente, pasamos &lt;code&gt;GLFW.newContext&lt;/code&gt; como fabrica.&lt;/p&gt;
&lt;p&gt;El formato describe que clase de imagenes vamos a estar dibujando en la ventana, por ej. cuantos canales de color va a tener y cuantos bit por color. Tambien describe si vamos a tener un &lt;strong&gt;depth buffer&lt;/strong&gt; o un &lt;strong&gt;stencil buffer&lt;/strong&gt; asociado a la ventana (voy a discutir que son más adelante en este tutorial, cuando detalle como dibujar). Puedes incluso crear un contexto que no posee una ventana, por ej. si quieres usar la GPU para generar imagenes y guardarlas a disco, en vez de mostrarlas en la pantalla. Ahora vamos a quedarnos con un formato de color RGB de 8 bits por cada uno de sus tres canales, sin &lt;em&gt;depth buffer&lt;/em&gt; ni &lt;em&gt;stencil buffer&lt;/em&gt;. El valor que describe este formato es &lt;code&gt;ContextFormatColor RGB8&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;El ultimo parametro para &lt;code&gt;runContextT&lt;/code&gt; es la acción monadica en la cual todo nuestro programa ocurre. Cuando esta acción retorna, la ventana es cerrada. Esta acción monadica tiene el tipo &lt;code&gt;ContextT w os f m a&lt;/code&gt;. Esto es un &lt;em&gt;monad transformer&lt;/em&gt;, es decir una monada que hereda las capacidades de otra monada de tipo &lt;code&gt;m&lt;/code&gt;. Para &lt;code&gt;ContextT&lt;/code&gt;, &lt;code&gt;m&lt;/code&gt; es el tipo de la monada en la cual ejecutamos &lt;code&gt;runContextT&lt;/code&gt;. En este, y muchos otros casos, es simplemente la monada &lt;code&gt;IO&lt;/code&gt;. Dentro de un monad transformer puedes usar la función &lt;code&gt;lift&lt;/code&gt; para ejecutar una acción en la monada heredada.&lt;/p&gt;
&lt;p&gt;GPipe usa algunos trucos con los tipos de datos, para asegurar que las variables que retornan sus acciones dentro del contexto, no salen de el. Este es el mismo mecanismo que usa la monada &lt;code&gt;ST&lt;/code&gt; para asegurarse que ninguna &lt;code&gt;STRef&lt;/code&gt; es retornada ni usada en otra invocación a &lt;code&gt;runST&lt;/code&gt;. El truco es que &lt;code&gt;runContextT&lt;/code&gt; usa algo llamado &lt;code&gt;rank-2 type&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;runContextT :: (MonadIO m, MonadAsyncException m)
            =&amp;gt; ContextFactory c ds w 
            -&amp;gt; ContextFormat c ds 
            -&amp;gt; (forall os. ContextT w os (ContextFormat c ds) m a) 
            -&amp;gt; m a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fijate que hay un modificador &lt;code&gt;forall&lt;/code&gt; para &lt;code&gt;os&lt;/code&gt;, local al argumento de la acción monadica &lt;code&gt;ContextT&lt;/code&gt;. Esto hace que cualquier objeto que referencie a &lt;code&gt;os&lt;/code&gt; este limitado a esta acción monadica.&lt;/p&gt;
&lt;p&gt;Es posible ejecutar otro &lt;code&gt;runContextT&lt;/code&gt; dentro de una monada &lt;code&gt;ContextT&lt;/code&gt;, el cual va a crear una segunda ventana con su propio contexto. Ya que estos contextos poseen su propio espacio de objetos, no pueden compartir entre ellos objetos que referencien al parametro de tipo &lt;code&gt;os&lt;/code&gt;. Esto es una limitación bastante grande y, la mayor parte de la veces que trabajes con varias ventanas, vas a querer dejarlos usar el mismo espacio de objetos. Esto se logra usando &lt;code&gt;runSharedContextT&lt;/code&gt;. Esta acción debe ser utilizada dentro de otro &lt;code&gt;ContextT&lt;/code&gt;, y la acción monadica que se pasa a esta función va a usar el mismo espacio de objetos que el &lt;code&gt;ContextT&lt;/code&gt; que la rodea, pero va a tener una ventana propia.&lt;/p&gt;
&lt;p&gt;El parametro &lt;code&gt;w&lt;/code&gt; en el tipo &lt;code&gt;ContextT&lt;/code&gt; es algo definido por la fabrica del contexto. Cuando usamos &lt;code&gt;GLFW.newContext&lt;/code&gt;, &lt;code&gt;w&lt;/code&gt; va a ser &lt;code&gt;GLFWWindow&lt;/code&gt;. Esto es un tipo opaco, asi que no puede usarlo directamente. A pesar de esto, nos permite usar &lt;code&gt;windowShouldClose&lt;/code&gt; y otras acciones del paquete GPipe-GLFW dentro de nuestro contexto. En nuestro programa &lt;em&gt;hello world&lt;/em&gt;, &lt;code&gt;windowShouldClose&lt;/code&gt; es usado para salir del &lt;code&gt;loop&lt;/code&gt; cuando el usuario cierra la ventana, al hacer click sobre la X en la esquina superior.&lt;/p&gt;
&lt;h2&gt;Renderizado - De eso se trata realmente&lt;/h2&gt;
&lt;p&gt;Ahora que tenemos nuestro contexto, hagamos algo de renderizado. Cualquier renderizado que haga en GPipe, va a seguir esta secuencia de operaciones:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/gpipe-part-01-sequence.svg&quot; alt=&quot;Secuencia de operaciones de GPipe&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Por lo pronto, todo renderizado de GPipe va a crear, a partir de un buffer de datos, un array de &lt;em&gt;vertices&lt;/em&gt; que serán ensamblados en un array de &lt;em&gt;primitivas&lt;/em&gt;. Hay tres clases de primitivas: puntos, lineas, y triangulos; pero vamos a trabajar casi exclusivamente con triangulos. El array de primitivas entonces se transforma en un stream de primitivas dentro de un &lt;em&gt;shader&lt;/em&gt;, permitiendonos aplicar transformaciones a esos vertices. Las primitivas luego son rasterizadas, es decir son cortadas en &lt;em&gt;fragmentos&lt;/em&gt; medidos en pixels, formando un stream de fragmentos. Este stream es luego dibujado en la ventana del contexto, o en una imagen fuera de pantalla.&lt;/p&gt;
&lt;p&gt;En la monada &lt;code&gt;ContextT&lt;/code&gt;, comenzamos creando un buffer de datos que es almacenado en la GPU. En nuestro ejemplo &lt;em&gt;hello world&lt;/em&gt; de más arriba, nuestro buffer es llamado &lt;code&gt;vertexBuffer&lt;/code&gt; y tiene 3 elementos, siendo cada uno una tupla &lt;code&gt;(B4 Float, B3 Float)&lt;/code&gt;. &lt;code&gt;B4&lt;/code&gt; y &lt;code&gt;B3&lt;/code&gt; son para un buffer las &lt;em&gt;&quot;representaciones&quot;&lt;/em&gt; de &lt;code&gt;V4&lt;/code&gt; y &lt;code&gt;V3&lt;/code&gt;, los tipos vectoriales del paquete &lt;em&gt;linear&lt;/em&gt;. Voy a dar más detalles sobre que son estas &lt;em&gt;&quot;representaciones&quot;&lt;/em&gt; en la siguiente parte de este tutorial, pero por ahora puedes pensar a &lt;code&gt;B4&lt;/code&gt; como otro nombre para &lt;code&gt;V4&lt;/code&gt; cuando lo usamos en un &lt;code&gt;Buffer&lt;/code&gt;. Despues de crear el buffer, escribimos tres valores dentro de él, a partir de una lista comun.&lt;/p&gt;
&lt;p&gt;Con una función llamada &lt;code&gt;render&lt;/code&gt; ejecutamos otra monada, convenientemente llamada... &lt;code&gt;Render&lt;/code&gt;. En esta monada usamos nuestro &lt;code&gt;Buffer&lt;/code&gt; para crear un &lt;code&gt;VertexArray&lt;/code&gt; con la función &lt;code&gt;newVertexArray&lt;/code&gt;. Viniendo de nuestro &lt;code&gt;vertexBuffer&lt;/code&gt;, &lt;code&gt;vertexArray&lt;/code&gt; tendrá 3 vertices, cada uno de los cuales tiene una tupla &lt;code&gt;(B4 Float, B3 Float)&lt;/code&gt;. Ahora debes preguntarte cual es la diferencia entre un &lt;code&gt;VertexArray&lt;/code&gt; y una &lt;code&gt;Buffer&lt;/code&gt;. Una pregunta verdaderamente razonable, pero me temo que vamos a tener que esperar hasta la siguiente parte de este tutorial para responderla, lo siento.&lt;/p&gt;
&lt;p&gt;Ahora que tenemos un &lt;code&gt;VertexArray&lt;/code&gt;, vamos a usarlo para crear un &lt;code&gt;PrimitiveArray&lt;/code&gt; de triangulos, usando la función &lt;code&gt;toPrimitiveArray&lt;/code&gt;. El argumento &lt;code&gt;TriangleList&lt;/code&gt;, que pasamos a la función, indica que queremos formar triangulos a partir de cada tres vertices consecutivos en un &lt;code&gt;vertexArray&lt;/code&gt;. Como solo hay tres vertices, &lt;code&gt;primitiveArray&lt;/code&gt; va a contener un solo triangulo.&lt;/p&gt;
&lt;p&gt;Mirando el grafico de arriba, tenemos que convertir este &lt;code&gt;PrimitiveArray&lt;/code&gt; en un &lt;code&gt;PrimitiveStream&lt;/code&gt; (estaras pensando, ¿otro nombre más para la misma cosa?) pero, ¿porque en el código solo vemos &lt;code&gt;shader primitiveArray&lt;/code&gt;?&lt;/p&gt;
&lt;h2&gt;Shaders - Un pequeño acercamiento&lt;/h2&gt;
&lt;p&gt;La caja gris en el grafico de arriba es llamada &lt;code&gt;Shader&lt;/code&gt;. Supongo que será poco sorprendente a esta altura pero, ¡tambien es una monada! La diferencia con ambas monadas, &lt;code&gt;ContextT&lt;/code&gt; y &lt;code&gt;Render&lt;/code&gt;, es que no podemos ejecutarla directamente, tiene que ser primero &lt;em&gt;compilada&lt;/em&gt;. Esta compilación es distinta a la que haces cuando ejecutas ghc, cabal, stack, o cualquier acceso directo que tengas en emacs. Esta compilación ocurre durante el tiempo de ejecución del programa, y usa un compilador que provee tu controlador grafico. La compilación puede tomar varios segundos, definitivamente no es algo que quieres hacer durante cada frame en por ej. un juego creado con GPipe.&lt;/p&gt;
&lt;p&gt;Una monada &lt;code&gt;Shader&lt;/code&gt; es compilada mediante la función &lt;code&gt;compileShader&lt;/code&gt;, que es ejecutada en tu monada &lt;code&gt;ContextT&lt;/code&gt;. &lt;code&gt;compileShader&lt;/code&gt; retornará una función que luego puedes ejecutar en una monada &lt;code&gt;Render&lt;/code&gt;. En nuestro ejemplo de arriba, compilamos el shader en una función a la que llamamos simplemente &lt;code&gt;shader&lt;/code&gt;. Este &lt;code&gt;shader&lt;/code&gt; es lo que vemos ejecutarse como ultima acción en la monada &lt;code&gt;Render&lt;/code&gt;, pasandole &lt;code&gt;primitiveArray&lt;/code&gt; como argumento.&lt;/p&gt;
&lt;p&gt;Demos ahora una mirada al &lt;code&gt;Shader&lt;/code&gt; en nuestro ejemplo. La primera acción que ejecutamos es &lt;code&gt;toPrimitiveStream&lt;/code&gt;. Esto cargará un &lt;code&gt;PrimitiveArray&lt;/code&gt; en algo llamado &lt;code&gt;PrimitiveStream&lt;/code&gt;. El &lt;code&gt;PrimitiveArray&lt;/code&gt; a cargar es seleccionado mediante la función pasada como argumento a &lt;code&gt;toPrimitiveStream&lt;/code&gt;, en este caso &lt;code&gt;id&lt;/code&gt;. Una monada &lt;code&gt;Shader&lt;/code&gt; es casi como una monada &lt;code&gt;Reader&lt;/code&gt;, ya que es cerrada sobre un entorno. Pero a diferencia de la monada &lt;code&gt;Reader&lt;/code&gt;, no hay una acción &lt;code&gt;ask&lt;/code&gt; por la cual puedes recuperar el entorno. En vez de esto, otras acciones, como &lt;code&gt;toPrimitiveStream&lt;/code&gt;, van a tomar una función que extrae valores de este entorno. Cada valor del entorno no es definido hasta que el shader es &lt;em&gt;ejecutado&lt;/em&gt;, es decir ni siquiera cuando es compilado. ¿Recuedas que pasamos &lt;code&gt;primitiveArray&lt;/code&gt; como argumento a nuestra función &lt;code&gt;shader&lt;/code&gt; compilada? Ese es el entorno que usamos en nuestro programa. Ya que la función pasada a &lt;code&gt;toPrimitiveStream&lt;/code&gt; quiere extraer un &lt;code&gt;PrimitiveArray&lt;/code&gt; del entorno, y nuestro entorno es un &lt;code&gt;PrimitiveArray&lt;/code&gt;, simplemente usamos &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Un &lt;code&gt;PrimitiveStream&lt;/code&gt; es tambien una secuencia de primitivas, pero vive dentro del shader y por lo tanto podriamos mapear funciones sobre él, las cuales correran sobre la GPU. &lt;code&gt;PrimitiveStream&lt;/code&gt; implementa el typeclass &lt;code&gt;Functor&lt;/code&gt;, y &lt;code&gt;fmap f primitiveStream&lt;/code&gt; retornará un nuevo &lt;code&gt;PrimitiveStream&lt;/code&gt; que es resultado de aplicar la función &lt;code&gt;f&lt;/code&gt; a cada vertice de cada primitiva en &lt;code&gt;primitiveStream&lt;/code&gt;. Mapear funciones sobre streams con &lt;code&gt;fmap&lt;/code&gt; en shaders es muchas veces más rapido que hacer la misma clase de operación en listas ordinarias, ya que estamos usando la GPU en vez del CPU. En nuestro ejemplo &quot;Hello world&quot;, no estamos realmente haciendo nada con las primitivas en nuestro &lt;code&gt;primitiveStream&lt;/code&gt; antes de pasarla a la función &lt;code&gt;rasterize&lt;/code&gt;. Pero antes de entrar en ese tema, dejame mencionar cual es el tipo de datos inferido de &lt;code&gt;primitiveStream&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;primitiveStream :: PrimitiveStream Triangles (V4 VFloat, V3 VFloat)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Como puedes ver, los tipos &lt;code&gt;B4&lt;/code&gt; y &lt;code&gt;B3&lt;/code&gt; que teniamos en nuestro buffer (y nuestros vertex array y primitive array), fueron transformados nuevamente en &lt;code&gt;V4&lt;/code&gt; y &lt;code&gt;V3&lt;/code&gt;, pero ¡los &lt;code&gt;Float&lt;/code&gt; dentro de ellos fueron aparentemente transformados en &lt;code&gt;VFloat&lt;/code&gt;! &lt;code&gt;VFloat&lt;/code&gt; es en realidad un sinonimo para el tipo &lt;code&gt;S V Float&lt;/code&gt;, el cual representa un &lt;code&gt;Float&lt;/code&gt; desplazado a un stream de vertices en la GPU, es decir ya no es más un &lt;code&gt;Float&lt;/code&gt; ordinario que puedes usar en cualquier función, solo puedes hacer con el cosas que la GPU soporta. Voy a discutir este tipo de datos con más detalle cuando revisemos los shaders con mayor profundidad en una parte posterior de este tutorial.&lt;/p&gt;
&lt;h2&gt;Rasterización&lt;/h2&gt;
&lt;p&gt;Incluso aunque nunca mapeemos ninguna función a nuestro &lt;code&gt;primitiveStream&lt;/code&gt; para ejecutarla en la GPU, ni tampoco al &lt;code&gt;fragmentShader&lt;/code&gt; que estamos por crear, todavia hay una operación que siempre hacemos en un shader la cual aprovecha el paralelismo masivo de la GPU: rasterización.&lt;/p&gt;
&lt;p&gt;Rasterización es el proceso de mapear una primitiva, por ej. un triangulo, a una grilla y generar fragmentos medidos en pixels. Los vertices de las primitivas de entrada son usados de dos maneras: primero, todos deben proveer una posición del vertice, asi el rasterizador sabe cuantos fragmentos generar; y segundo, proveer valores que seran interpolados linealmente entre todos los vertices de la primitiva, para crear valores unicos en cada fragmento generado.&lt;/p&gt;
&lt;p&gt;El primer argumento para &lt;code&gt;rasterize&lt;/code&gt;, es una función que extrae tres parametros del entorno del shader: que lado de la primitiva rasterizar, las posición y el tamaño del &lt;em&gt;view port&lt;/em&gt;, y el rango de profundidad (&lt;em&gt;depth range&lt;/em&gt;) del fragmento. En nuestro ejemplo, sabemos todos los parametros de antemano y no necesitamos obtenerlos del entorno del shader, por eso es que usamos la función &lt;code&gt;const&lt;/code&gt;. Los parametros que proveemos a &lt;code&gt;rasterize&lt;/code&gt; le dicen que debe rasterizar ambos lados de cada triangulo, que el view port tiene (0,0) como coordenada inferior izquierda y tanto altura como ancho de 500 pixels, y finalmente que el rango de profundidad es [0,1]. Más sobre esto en un momento.&lt;/p&gt;
&lt;p&gt;Las posiciones de los vertices son coordenadas 3D en un espacio de vista canonico (&lt;em&gt;canonical view space&lt;/em&gt;). Durante la rasterización, estos van a ser transformados en el view port en espacio de pantalla en pixels, donde la posición (-1,-1,z) en el espacio de vista canonico va a ser mapeado a la esquina inferior izquierda del view port (en nuestro caso (0,0)), y (1,1,z) va a ser mapeado a la esquina superior derecha (en nuestro caso (500,500)). Para ser más precisos, el fragmento en la esquina inferior izquierda en nuestro caso va a tener realmente la coordenada de pixel (0.5,0.5), y el fragmento superior derecho que generaremos tendrá coordenada (499.5,499.5).&lt;/p&gt;
&lt;p&gt;Todo fragmento tambien tiene un valor de profundidad en el rango [0,1]. En la rasterización nosotros especificamos, con el parametro &lt;code&gt;DepthRange&lt;/code&gt;, como mapear la coordenada canonica z a este rango. Una coordenada z con valor -1 será mapeada al primer parametro de &lt;code&gt;DepthRange&lt;/code&gt;, y una coordenada z con valor 1 será mapeada al segundo parametro de &lt;code&gt;DepthRange&lt;/code&gt;. En nuestro ejemplo, nosotros mapeamos las coordenadas z en el espacio de vista canonico de rango [0,1] al rango de profundidad [0,1]. La convencion usada por &lt;a href=&quot;https://hackage.haskell.org/package/linear-1.19.1.3/docs/Linear-Projection.html&quot;&gt;Linear.Projection&lt;/a&gt;, y muchas otras librerias matemáticas para OpenGl, es que la coordenada z de 1 en el espacio de vista canonico es considerada la mas alejada y -1 la mas cercana, pero en realidad eres libre de usar cualquier combinacion que gustes. Cualquier fragmento con un valor fuera del rango de profundidad [0,1] será descartado, asi cualquier parte de las primitivas que intersectan la caja [(-1,-1,-1),(1,1,1)] en el espacio de vista canonico se convertirá en fragmentos en el view port. Esta caja es normalmente conocida como volumen de vista canonica (&lt;em&gt;canonical view volume&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;La posición de un vertice en el espacio de vista canonico se provee en realidad como un &lt;code&gt;V4 VFloat&lt;/code&gt;, conocido como una coordenada 3D homogenea, donde &lt;code&gt;V4 x y z w&lt;/code&gt; posee la posición 3D (x/w,y/w,z/w). Los tres vertices del triangulo en nuestro ejemplo usan 1 para la componente w, asi en este caso son simplemente coordenadas 3D comunes. Cuando se aplica &quot;proyeccion perspectiva&quot; (donde los objetos aparecen más pequeños cuanto más lejos estan, lo cual es standard en la mayoria de las aplicaciones 3D), la componente w no será 1. La razon por la cual el rasterizador quiere que w sea pasada de forma explicita en vez de hacer que dividamos los componentes por nuestra cuenta (mapeando una función de esa indole sobre el stream de primitivas), es que esta componente w es tambien usada cuando se realiza la interpolación de todos los demas valores del vertice. Voy a demostrar como funciona esta interpolación con corrección de perspectiva en una parte posterior, cuando veamos textures y samplers.&lt;/p&gt;
&lt;p&gt;Ahora que hemos calculado que fragmentos generar para cada primitiva, y cuales posiciones de pantalla y valores de profundidad van a tener, podemos interpolar los demas valores de los vertices. El segundo argumento de la función &lt;code&gt;rasterize&lt;/code&gt; es un stream de primitivas con tipo&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;FragmentInput a =&amp;gt; PrimitiveStream p (V4 VFloat, a)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Y retorna un stream de fragmentos con tipo&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;FragmentInput a =&amp;gt; FragmentStream (FragmentFormat a)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Esto significa que cada vertice tiene una posición homogenea como hemos discutido recien, pero tambien algun valor extra de tipo &lt;code&gt;a&lt;/code&gt; que va a ser transformado en un valor de tipo &lt;code&gt;FragmentFormat a&lt;/code&gt; en cada fragmento. Estos valores son producidos interpolando linealmente los valores de los vertices sobre toda la primitiva para cada fragmento. En nuestro ejemplo, &lt;code&gt;a&lt;/code&gt; es &lt;code&gt;V3 VFloat&lt;/code&gt;, representando el color de cada vertice. &lt;code&gt;FragmentFormat a&lt;/code&gt; es un tipo asociado en la clase &lt;code&gt;FragmentInput&lt;/code&gt;, y &lt;code&gt;FragmentFormat (V3 VFloat)&lt;/code&gt; evalua a &lt;code&gt;V3 FFloat&lt;/code&gt;. &lt;code&gt;FFloat&lt;/code&gt; es como &lt;code&gt;VFloat&lt;/code&gt;, una versión desplazada de &lt;code&gt;Float&lt;/code&gt;, pero esta vez a un stream de fragmentos. Distinguimos los valores desplazados a un stream de vertices, de los valores desplazados a un stream de fragmentos, ya que la GPU no soporta exactamente el mismo conjunto de operaciones sobre ellos.&lt;/p&gt;
&lt;h2&gt;Dibujando e intercambiando&lt;/h2&gt;
&lt;p&gt;Lo ultimo que hacemos en nuestro shader, ahora que tenemos el &lt;code&gt;fragmentStream&lt;/code&gt;, es dibujar los fragmentos en la ventana. &lt;code&gt;drawContextColor&lt;/code&gt; toma como argumento a &lt;code&gt;fragmentStream&lt;/code&gt;, pero tambien, asi como la mayoria de las demas acciones en la monada &lt;code&gt;Shader&lt;/code&gt;, toma una función que extrae parametros del entorno del shader. En este caso el parametro extraido es un valor de tipo &lt;code&gt;ContextColorOption&lt;/code&gt;, el cual especifica como los fragmentos deden ser combinados con los valores previos en la ventana. El valor que proveemos en nuestro ejemplo (nuevamente usando &lt;code&gt;const&lt;/code&gt;, ya que no depende del entorno del shader), esta especificando que cada fragmento debe sobreescribir completamente el valor previo en la ventana. Voy a dedicar una parte completa de este tutorial a como dibujar, asi estos parametros seran explicados en detalle más adelante.&lt;/p&gt;
&lt;p&gt;Ya que nuestra ventana fue creada con formato &lt;code&gt;RGB8&lt;/code&gt;, el stream de fragmentos necesita contener valores de color de tipo &lt;code&gt;V3 FFloat&lt;/code&gt;. Convenientemente, es el tipo exacto que tiene nuestro &lt;code&gt;fragmentStream&lt;/code&gt; como resultado de la rasterización. Sin embargo, en la mayoria de los programas basados en GPipe vas a mapear funciones via &lt;code&gt;fmap&lt;/code&gt; sobre el stream de fragmentos, para transformar los valores interpolados de la rasterizacion en el formato de color que es requerido por la ventana.&lt;/p&gt;
&lt;p&gt;Dibujar es la unica acción en el shader que posee un efecto secundario: en este caso el buffer trasero de la ventana es alterado. Una ventana tiene (al menos) dos buffers, uno llamado buffer frontal que es mostrado en la pantalla, y otro que llamamos buffer trasero donde los shaders estan dibujando. Cuando la acción &lt;code&gt;shader primitiveArray&lt;/code&gt; en la monada &lt;code&gt;Render&lt;/code&gt; retorna, el buffer trasero sera actualizado. Para presentar en la pantalla esta nueva imagen renderizada, necesitamos llamar a &lt;code&gt;swapContextBuffers&lt;/code&gt; dentro de nuestra monada &lt;code&gt;ContextT&lt;/code&gt;. Esto le va a indicar al hardware grafico que intercambie los buffers frontal y trasero. No se va a realizar ninguna copia de memoria, sino solamente un intercambio de valores de punteros, asi que es bastante efectivo. Sin embargo, &lt;code&gt;swapContextBuffers&lt;/code&gt; puede bloquearse momentaneamente si tratas de presentar imagenes mas rapido que la pantalla pueda actualizarse, pero esto es usualmente algo bueno, ya que de otra forma estarias gastando ciclos de GPU y CPU produciendo más imagenes de las que pueden presentarse.&lt;/p&gt;
&lt;p&gt;Hay una linea en la acción &lt;code&gt;Render&lt;/code&gt; de nuestro ejemplo, que omití antes descaradamente: &lt;code&gt;clearContextColor (V3 0 0 0)&lt;/code&gt;. Esta acción ocurre antes de ejecutar el shader, y es usada para setear cada pixel en los contenidos previos del buffer trasero a un valor constante, en este caso &lt;code&gt;V3 0 0 0&lt;/code&gt;, es decir, color negro. Luego de un intercambio, los contenidos del buffer trasero son indefinidos, asi que es siempre una buena idea comenzar cada frame haciendo limpieza luego de &lt;code&gt;swapContextBuffers&lt;/code&gt;. Limpiar y ejecutar shaders son dos acciones de la monada &lt;code&gt;Render&lt;/code&gt; que tienen efectos secundarios.&lt;/p&gt;
&lt;p&gt;Esto concluye la primer parte de este tutorial. La proxima vez voy a escribir detalladamente sobre &lt;code&gt;Buffer&lt;/code&gt; y &lt;code&gt;PrimitiveArray&lt;/code&gt;.&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>Enviroment variables using fish shell</title><id>https://rainbyte.net.ar/posts/160207-01-env-vars-with-fish.html</id><updated>2016-02-07T02:46:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/160207-01-env-vars-with-fish.html" rel="alternate"/><published>2016-02-07T02:46:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2016-02-07 02:46:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;fish&apos;.&quot; href=&quot;/tags/fish.html&quot;&gt;fish&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;shell&apos;.&quot; href=&quot;/tags/shell.html&quot;&gt;shell&lt;/a&gt;
    
&lt;/div&gt;

&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;Sometimes we need to &lt;em&gt;export&lt;/em&gt; some value as an &lt;code&gt;env var&lt;/code&gt; (eg. android sdk path).
It is important to know how to do this well for smooth system administration.&lt;/p&gt;
&lt;p&gt;Each shell has its own way to manage environment, I&apos;m using fish shell.&lt;/p&gt;
&lt;p&gt;In order to list current vars, standard &lt;code&gt;env&lt;/code&gt; command is available.&lt;/p&gt;
&lt;h2&gt;Local env vars&lt;/h2&gt;
&lt;p&gt;We could run an app with custom enviroment vars, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;env LALA=&apos;foo bar&apos; some_cmd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This does not always work, because &lt;code&gt;env&lt;/code&gt; bypasses our shell.&lt;/p&gt;
&lt;p&gt;In those situations, we could use &lt;code&gt;set&lt;/code&gt; instead:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set -lx LALA=&apos;foo bar&apos;; some_cmd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;-l&lt;/code&gt; switch means &lt;em&gt;local scope&lt;/em&gt;, the variable is temporal.&lt;/p&gt;
&lt;h2&gt;Persistent env vars&lt;/h2&gt;
&lt;p&gt;When we need env vars to be &lt;em&gt;persistent&lt;/em&gt; only across a session, we use &lt;code&gt;global&lt;/code&gt; ones (&lt;code&gt;-g&lt;/code&gt; switch):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set -gx LALA=&apos;foo bar&apos;
some_cmd
other_cmd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we could use &lt;code&gt;universal&lt;/code&gt; env vars, which are &lt;em&gt;fully persistent&lt;/em&gt; across multiple sessions (&lt;code&gt;-U&lt;/code&gt; switch).&lt;/p&gt;
&lt;p&gt;For example, I used them in order to configure android sdk, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set -U ANDROID_HOME /path/to/android/sdk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Universal&lt;/code&gt; env vars are &lt;em&gt;persistent&lt;/em&gt; across reboots, you can inspect them using &lt;code&gt;set -U&lt;/code&gt; cmd.&lt;/p&gt;
&lt;h2&gt;Path management&lt;/h2&gt;
&lt;p&gt;Changing the &lt;code&gt;PATH&lt;/code&gt; env var is an special case. We cannot modify it directly, because it could be overwritten by the shell.&lt;/p&gt;
&lt;p&gt;In order to overcome this situation, fish provides the &lt;code&gt;fish_user_paths&lt;/code&gt; variable, which is automatically merged to &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We could add some custom bin directory (e.g. node_modules bin dir), like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set -U fish_user_paths $fish_user_paths /path/to/node_modules/bin
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this way we preserve previously added paths, and the new dir is only appended to &lt;code&gt;fish_user_paths&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The shell automatically adds the custom paths to the &lt;code&gt;PATH&lt;/code&gt; var each time a session is started.&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>How-to update a git submodule</title><id>https://rainbyte.net.ar/posts/150702-02-how-to-update-a-git-submodule.html</id><updated>2015-07-02T04:29:59-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/150702-02-how-to-update-a-git-submodule.html" rel="alternate"/><published>2015-07-02T04:29:59-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2015-07-02 04:29:59
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;workflow&apos;.&quot; href=&quot;/tags/workflow.html&quot;&gt;workflow&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;git&apos;.&quot; href=&quot;/tags/git.html&quot;&gt;git&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;I do not use git submodules too often, so I&apos;ll write this recipe here, for future reference.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;When we have a git repo with a submodule inside, some steps are needed to update both in sync.&lt;br /&gt;
This occurs because, the parent repo and the submodule, are actually two independent repos.&lt;/p&gt;
&lt;p&gt;This is the workflow I use to update a submodule:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Work inside the submodule:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$ # edit &amp;lt;some files&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$ git add &amp;lt;some files&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now we have some changes ready to commit and push them:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$ git commit -m &quot;Edited &amp;lt;some files&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$ git push&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, we tell the parent repo that the submodule has changed:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$ cd the/parent/repo/path&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$ git add the/submodule/repo/path&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$ git commit -m &quot;Updated the submodule&quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$ git push&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Syncing everytime a change is made to the submodule &lt;strong&gt;is not advisable&lt;/strong&gt;, think carefully before doing it.&lt;br /&gt;
Sometimes we should &lt;strong&gt;NOT do it&lt;/strong&gt; at all (e.g. there are
compatibility breaking changes).&lt;/p&gt;
&lt;p&gt;The parent repo could point to a previous (&lt;em&gt;and safe&lt;/em&gt;) version of the submodule all the required time.&lt;br /&gt;
At least while is being adapted to assimilate the submodule updates.&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>How-to decrease gnome title-bar height</title><id>https://rainbyte.net.ar/posts/150702-01-how-to-decrease-gnome-titlebar-height.html</id><updated>2015-07-02T03:15:07-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/150702-01-how-to-decrease-gnome-titlebar-height.html" rel="alternate"/><published>2015-07-02T03:15:07-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2015-07-02 03:15:07
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;gnome&apos;.&quot; href=&quot;/tags/gnome.html&quot;&gt;gnome&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;snippets&apos;.&quot; href=&quot;/tags/snippets.html&quot;&gt;snippets&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;css&apos;.&quot; href=&quot;/tags/css.html&quot;&gt;css&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;I&apos;ve started using &lt;a href=&quot;https://www.mozilla.org/firefox&quot;&gt;Firefox&lt;/a&gt; again, and after some time I noticed that Gnome window title-bars were eating a lot of screen space.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;To solve the issue, I&apos;ve tried installing &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/hide-caption-titlebar-plus-sma/&quot;&gt;a plugin&lt;/a&gt;, but I was not too happy with the result (even after some custom tweaks).&lt;br /&gt;
Later, I gave up with the plugin, and started searching for other solution, reading various sources (like forums).&lt;/p&gt;
&lt;p&gt;Finally, a &lt;a href=&quot;https://wiki.archlinux.org/index.php/GNOME#Titlebar_height&quot;&gt;good hint&lt;/a&gt; appeared inside &lt;a href=&quot;https://wiki.archlinux.org&quot;&gt;the ArchWiki&lt;/a&gt; (a wonderful source of reliable information).&lt;br /&gt;
After tweaking the snippet a bit, I added it to &lt;code&gt;~/.config/gtk-3.0/gtk.css&lt;/code&gt;, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;.header-bar.default-decoration {
    padding-top: 1px;
    padding-bottom: 1px;
    font-size: 0.5em;
}

.header-bar.default-decoration .button.titlebutton {
    padding-top: 1px;
    padding-bottom: 1px;
    border-width: 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An that&apos;s all, no plugin needed and it is useful system wide (at least for apps which don&apos;t support client side decorations).&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>Grouping by key with Python</title><id>https://rainbyte.net.ar/posts/150519-01-grouping-by-key-with-python.html</id><updated>2015-05-19T23:02:37-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/150519-01-grouping-by-key-with-python.html" rel="alternate"/><published>2015-05-19T23:02:37-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2015-05-19 23:02:37
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;python&apos;.&quot; href=&quot;/tags/python.html&quot;&gt;python&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;snippets&apos;.&quot; href=&quot;/tags/snippets.html&quot;&gt;snippets&lt;/a&gt;&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;batch&apos;.&quot; href=&quot;/tags/batch.html&quot;&gt;batch&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;Today I had to process some data, which was inside an unordered list, using the Python language.&lt;/p&gt;
&lt;p&gt;Some computations employed all the list items, others were based only on related ones.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;The data was arranged in tuples, each one contained a main value among others.&lt;/p&gt;
&lt;p&gt;That value (let&apos;s call it &quot;key&quot;), identified a relation with other tuples.&lt;/p&gt;
&lt;p&gt;Simplifying it, quite a bit, was something similar to this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;items = [(1, &quot;a&quot;), (3, &quot;q&quot;), (2, &quot;c&quot;), (2, &quot;x&quot;), (1, &quot;z&quot;)]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem could be solved using some nested &quot;while&quot; iterations.&lt;/p&gt;
&lt;p&gt;But actually, I wanted something more brief and readable.&lt;/p&gt;
&lt;p&gt;Then, I looked for an alternative, and found itertools.&lt;/p&gt;
&lt;p&gt;First I&apos;ve loaded the required module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from itertools import groupby
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, the final solution was much like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;for key, group in groupby(sorted(items), lambda x: x[0]):
    # Do something with the key
    print(key)
    for tuple in group:
        # Process each tuple with same key
        print(tuple)
    # Other statements
    print(&quot;^^^^^^^^^&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are some remarkable points in this code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The list needs to be &lt;code&gt;sorted&lt;/code&gt; previously, so keys can be matched up.&lt;/li&gt;
&lt;li&gt;I&apos;ve used a &lt;code&gt;lambda&lt;/code&gt; in order to select which element is the key.&lt;/li&gt;
&lt;li&gt;The key can be accessed individually.&lt;/li&gt;
&lt;li&gt;Related tuples can accessed via the group variable.&lt;/li&gt;
&lt;li&gt;Each item inside each group still contains the key.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This code would print something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1
(1, &apos;a&apos;)
(1, &apos;z&apos;)
^^^^^^^^^
2
(2, &apos;c&apos;)
(2, &apos;x&apos;)
^^^^^^^^^
3
(3, &apos;q&apos;)
^^^^^^^^^
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the end, this method was cleaner than using iterations by hand.&lt;/p&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry><entry><title>Initial post</title><id>https://rainbyte.net.ar/posts/150517-01-initial-post.html</id><updated>2015-05-17T21:01:00-03:00</updated><author><name>rainbyte</name></author><link href="https://rainbyte.net.ar/posts/150517-01-initial-post.html" rel="alternate"/><published>2015-05-17T21:01:00-03:00</published><summary type="html">&lt;div class=&quot;info&quot;&gt;
    Posted on 2015-05-17 21:01:00
    
        by rainbyte
    
&lt;/div&gt;

&lt;div class=&quot;info&quot;&gt;
    
        Tags:&amp;nbsp;&lt;a title=&quot;All pages tagged &apos;hello&apos;.&quot; href=&quot;/tags/hello.html&quot;&gt;hello&lt;/a&gt;
    
&lt;/div&gt;

&lt;p&gt;Just wanted to say hello for first time! :)&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;&lt;img src=&quot;/images/Hello-World.png&quot; alt=&quot;See the world&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Let&apos;s try some example code with markdown and pygments:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-scheme&quot;&gt;#lang racket

(define (say-hello!)
  (printf &quot;Hello world!\n&quot;))
&lt;/code&gt;&lt;/pre&gt;



&lt;div id=&quot;gh-comments-list&quot;&gt;
    Comments are not open for this post yet.
&lt;/div&gt;
</summary></entry></feed>